From 4b06d756c53678fee39ef6a5e935c2875424484f Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Mon, 9 Aug 2021 09:53:15 +1000 Subject: [PATCH 01/76] Update index.tsx (#6278) --- docs/pages/updates/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index 65f93a1638a..b15ff603327 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -143,6 +143,7 @@ export default function WhatsNew() { , and subscribe to notifications on GitHub. + Date: Tue, 10 Aug 2021 10:57:27 +1000 Subject: [PATCH 02/76] Fix updates bit on the website (#6287) --- docs/components/Markdown.tsx | 8 ++------ docs/pages/releases/2021-03-22.mdx | 4 ++-- docs/pages/releases/2021-03-23.mdx | 4 ++-- docs/pages/releases/2021-03-30.mdx | 4 ++-- docs/pages/releases/2021-04-06.mdx | 4 ++-- docs/pages/releases/2021-04-20.mdx | 4 ++-- docs/pages/releases/2021-05-03.mdx | 4 ++-- docs/pages/releases/2021-05-05.mdx | 4 ++-- docs/pages/releases/2021-05-11.mdx | 4 ++-- docs/pages/releases/2021-05-17.mdx | 4 ++-- docs/pages/releases/2021-05-19.mdx | 4 ++-- docs/pages/releases/2021-06-02.mdx | 4 ++-- docs/pages/releases/2021-06-15.mdx | 4 ++-- docs/pages/releases/2021-06-28.mdx | 4 ++-- docs/pages/releases/2021-06-29.mdx | 4 ++-- docs/pages/releases/2021-06-30.mdx | 4 ++-- docs/pages/releases/2021-07-13.mdx | 4 ++-- docs/pages/releases/2021-07-29.mdx | 4 ++-- docs/pages/releases/index.mdx | 4 ++-- docs/pages/updates/index.tsx | 8 ++++---- docs/pages/updates/prisma-day-2021.mdx | 4 ++-- docs/pages/updates/roadmap.tsx | 4 ++-- docs/pages/updates/whats-new-in-v6.mdx | 4 ++-- 23 files changed, 48 insertions(+), 52 deletions(-) diff --git a/docs/components/Markdown.tsx b/docs/components/Markdown.tsx index 43b2e9109f8..02b8aa3f663 100644 --- a/docs/components/Markdown.tsx +++ b/docs/components/Markdown.tsx @@ -45,13 +45,9 @@ export function Markdown({ ); } -export async function getServerSideProps() { +export async function getStaticProps() { const { readdirSync } = require('fs'); - const { normalize } = require('path'); - const dir = __dirname.endsWith('/server') - ? normalize(`${__dirname}/../../pages/releases`) - : normalize(`${__dirname}/../../../pages/releases`); - + const dir = __dirname.replace(/docs.+$/, 'docs/pages/releases'); const releases = (readdirSync(dir, 'utf8') as Array) .filter(name => !name.startsWith('.') && !name.startsWith('index')) .map(name => name.replace('.mdx', '')) diff --git a/docs/pages/releases/2021-03-22.mdx b/docs/pages/releases/2021-03-22.mdx index f9e9636ac18..61397a86cbb 100644 --- a/docs/pages/releases/2021-03-22.mdx +++ b/docs/pages/releases/2021-03-22.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 22nd March 2021 @@ -50,4 +50,4 @@ Now you can include negative values for `float`, `decimal` and `integer` fields. You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-03-22) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-03-23.mdx b/docs/pages/releases/2021-03-23.mdx index cb792f3bdcb..4138c78c47c 100644 --- a/docs/pages/releases/2021-03-23.mdx +++ b/docs/pages/releases/2021-03-23.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 23rd March 2021 @@ -23,4 +23,4 @@ Mitchell [solved a bug](https://github.com/keystonejs/keystone/pull/5168) where You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-03-23) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-03-30.mdx b/docs/pages/releases/2021-03-30.mdx index 082c8d8a92c..67bc3a29477 100644 --- a/docs/pages/releases/2021-03-30.mdx +++ b/docs/pages/releases/2021-03-30.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 30th March 2021 @@ -44,4 +44,4 @@ We fixed a bug that existed in `updateMany` on lists with declarative access con You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-03-30) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-04-06.mdx b/docs/pages/releases/2021-04-06.mdx index 3255807b507..659f1428147 100644 --- a/docs/pages/releases/2021-04-06.mdx +++ b/docs/pages/releases/2021-04-06.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 6th April 2021 @@ -38,4 +38,4 @@ Pagination in the Admin UI has fresh styles and is easier to use. You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-04-06) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-04-20.mdx b/docs/pages/releases/2021-04-20.mdx index 728d313d133..3dae3c770ff 100644 --- a/docs/pages/releases/2021-04-20.mdx +++ b/docs/pages/releases/2021-04-20.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; # Release: 20th April 2021 @@ -60,4 +60,4 @@ const [post] = await context.db.lists.Post.findMany({ You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-04-20) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-05-03.mdx b/docs/pages/releases/2021-05-03.mdx index 8c8586ebe81..d701f6a165a 100644 --- a/docs/pages/releases/2021-05-03.mdx +++ b/docs/pages/releases/2021-05-03.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 3rd May 2021 @@ -27,4 +27,4 @@ This release involved a bunch of busywork behind the scenes in Keystone 6. Strip You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-05-03) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-05-05.mdx b/docs/pages/releases/2021-05-05.mdx index 35fcb410e35..13b7458d10e 100644 --- a/docs/pages/releases/2021-05-05.mdx +++ b/docs/pages/releases/2021-05-05.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 5th May 2021 @@ -20,4 +20,4 @@ If you look closely you’ll see the core team working on example projects to sh You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-05-05) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-05-11.mdx b/docs/pages/releases/2021-05-11.mdx index 44463a14382..c1d075c405c 100644 --- a/docs/pages/releases/2021-05-11.mdx +++ b/docs/pages/releases/2021-05-11.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 11th May 2021 @@ -21,4 +21,4 @@ A bunch of admin UI tweaks in this release, among other minor fixes. We also hav You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-05-11) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-05-17.mdx b/docs/pages/releases/2021-05-17.mdx index d64a04de378..a3cf8d2f729 100644 --- a/docs/pages/releases/2021-05-17.mdx +++ b/docs/pages/releases/2021-05-17.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 17th May 2021 @@ -24,4 +24,4 @@ Thanks to @cameronbraid for spotting a [session issue](https://github.com/keysto You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-05-17) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-05-19.mdx b/docs/pages/releases/2021-05-19.mdx index 17fb68d746c..86e646e5ad7 100644 --- a/docs/pages/releases/2021-05-19.mdx +++ b/docs/pages/releases/2021-05-19.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 19th May 2021 @@ -35,4 +35,4 @@ If you were directly importing from `@keystone-next/admin-ui` you can now import You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-05-19) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-06-02.mdx b/docs/pages/releases/2021-06-02.mdx index e5d3e8e1dbb..42dc7d7f6cf 100644 --- a/docs/pages/releases/2021-06-02.mdx +++ b/docs/pages/releases/2021-06-02.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 2nd June 2021 @@ -184,4 +184,4 @@ We've updated our Prisma dependency from `2.22.1` to `2.24.0`! Check out the [Pr You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-06-02) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-06-15.mdx b/docs/pages/releases/2021-06-15.mdx index 6e04474584d..cd3639e4206 100644 --- a/docs/pages/releases/2021-06-15.mdx +++ b/docs/pages/releases/2021-06-15.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 15th June 2021 @@ -93,4 +93,4 @@ We've updated our Prisma dependencies to `2.24.1`, check out the [Prisma release You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-06-15) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-06-28.mdx b/docs/pages/releases/2021-06-28.mdx index a1f85f4fe5a..4a6d7ccebc7 100644 --- a/docs/pages/releases/2021-06-28.mdx +++ b/docs/pages/releases/2021-06-28.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 28th June 2021 @@ -64,4 +64,4 @@ We've updated our Prisma dependencies to `2.25.0`, check out the [Prisma release You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-06-28) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-06-29.mdx b/docs/pages/releases/2021-06-29.mdx index a140e784a92..399ce1a5aab 100644 --- a/docs/pages/releases/2021-06-29.mdx +++ b/docs/pages/releases/2021-06-29.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 29th June 2021 @@ -64,4 +64,4 @@ config({ You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-06-29) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-06-30.mdx b/docs/pages/releases/2021-06-30.mdx index b8bf531d523..abfedc3d0e2 100644 --- a/docs/pages/releases/2021-06-30.mdx +++ b/docs/pages/releases/2021-06-30.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 30th June 2021 @@ -23,4 +23,4 @@ We've discovered an issue where `cloudinaryImage` and `relationship` fields were You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-06-30) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-07-13.mdx b/docs/pages/releases/2021-07-13.mdx index a5c1569c921..5e84262da4f 100644 --- a/docs/pages/releases/2021-07-13.mdx +++ b/docs/pages/releases/2021-07-13.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 13th July 2021 @@ -69,4 +69,4 @@ Our `packages-next` folder has moved over to `packages` as part of our push to a You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-07-13) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/2021-07-29.mdx b/docs/pages/releases/2021-07-29.mdx index b4a23c1902e..007b1aa015c 100644 --- a/docs/pages/releases/2021-07-29.mdx +++ b/docs/pages/releases/2021-07-29.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; # Release: 29th July 2021 @@ -97,4 +97,4 @@ Updated Prisma dependencies to `2.27.0`, check out the [Prisma releases page](ht You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-07-29) on GitHub. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/releases/index.mdx b/docs/pages/releases/index.mdx index 67512ebed1e..538727144f1 100644 --- a/docs/pages/releases/index.mdx +++ b/docs/pages/releases/index.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { Emoji } from '../../components/primitives/Emoji'; import { Status } from '../../components/primitives/Status'; @@ -79,4 +79,4 @@ Prisma migrations , Noteworthy bug-squashing < ?> 🔎 You can also find all the **Keystone 6** releases on [GitHub](https://github.com/keystonejs/keystone/releases)! export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index b15ff603327..a26302df2fd 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -3,7 +3,7 @@ import { HTMLAttributes, ReactNode } from 'react'; import { jsx } from '@emotion/react'; import Link from 'next/link'; -import { getServerSideProps } from '../../components/Markdown'; +import { getStaticProps } from '../../components/Markdown'; import { InlineCode } from '../../components/primitives/Code'; import { Button } from '../../components/primitives/Button'; import { Alert } from '../../components/primitives/Alert'; @@ -190,7 +190,7 @@ export default function WhatsNew() { frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen - > + /> Follow along in with the repo @@ -247,7 +247,7 @@ export default function WhatsNew() { frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen - > + /> @@ -397,4 +397,4 @@ export default function WhatsNew() { ); } -export { getServerSideProps }; +export { getStaticProps }; diff --git a/docs/pages/updates/prisma-day-2021.mdx b/docs/pages/updates/prisma-day-2021.mdx index 38cb1c75b41..56b736058c4 100644 --- a/docs/pages/updates/prisma-day-2021.mdx +++ b/docs/pages/updates/prisma-day-2021.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; # Prisma Day 2021 Talk @@ -110,4 +110,4 @@ So this is our take on what that looks like. I'd love you to check it out, let u Thanks for having me. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } diff --git a/docs/pages/updates/roadmap.tsx b/docs/pages/updates/roadmap.tsx index b0831f18c8e..6a66741b49b 100644 --- a/docs/pages/updates/roadmap.tsx +++ b/docs/pages/updates/roadmap.tsx @@ -2,7 +2,7 @@ import { ComponentProps, Fragment, ReactNode } from 'react'; import { jsx } from '@emotion/react'; -import { getServerSideProps } from '../../components/Markdown'; +import { getStaticProps } from '../../components/Markdown'; import { InlineCode } from '../../components/primitives/Code'; import { Button } from '../../components/primitives/Button'; import { Highlight } from '../../components/primitives/Highlight'; @@ -416,4 +416,4 @@ export default function Roadmap() { ); } -export { getServerSideProps }; +export { getStaticProps }; diff --git a/docs/pages/updates/whats-new-in-v6.mdx b/docs/pages/updates/whats-new-in-v6.mdx index f790b456ba9..87c87363cc1 100644 --- a/docs/pages/updates/whats-new-in-v6.mdx +++ b/docs/pages/updates/whats-new-in-v6.mdx @@ -1,4 +1,4 @@ -import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Markdown, getStaticProps } from '../../components/Markdown'; import { SubscribeForm } from '../../components/SubscribeForm'; import { Badge } from '../../components/primitives/Badge'; import { Emoji } from '../../components/primitives/Emoji'; @@ -58,4 +58,4 @@ We also have new reference examples for how to use advanced features, like imple roles-based access control system. export default ({ children, ...props }) => {children}; -export { getServerSideProps } +export { getStaticProps } From 4746a229bf9262269707406df32ecf30bd744ae2 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Tue, 10 Aug 2021 11:31:48 +1000 Subject: [PATCH 03/76] Content management update (#6282) * Add Wes Testimonial. Cleanup. * Typos --- docs/pages/for-content-management.tsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/pages/for-content-management.tsx b/docs/pages/for-content-management.tsx index f519c175973..4c86ed3b8a8 100644 --- a/docs/pages/for-content-management.tsx +++ b/docs/pages/for-content-management.tsx @@ -110,6 +110,16 @@ export default function ForOrganisations() { /> + + I love how Keystone’s access control lets me declare every single Create, Read, Update, + and Delete operation at both the model and field level. + It’s my favorite way of implementing Auth. +
@@ -261,7 +271,12 @@ export default function ForOrganisations() { - + The new @KeystoneJS rich text editor has incredible inline React component support, including editing props and everything! @@ -309,9 +324,6 @@ export default function ForOrganisations() { - {/* - Try the example → - */} Relationships guide → From 512b8deb5af77f5301506ac93bc39486285a9b63 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Tue, 10 Aug 2021 11:36:05 +1000 Subject: [PATCH 04/76] Fixed whitespace (#6283) --- docs/components/content/MWrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/components/content/MWrapper.tsx b/docs/components/content/MWrapper.tsx index 62aa670d77c..b620956764b 100644 --- a/docs/components/content/MWrapper.tsx +++ b/docs/components/content/MWrapper.tsx @@ -14,7 +14,7 @@ export function MWrapper({ as: Tag = 'div', ...props }: MWrapperProps) { return ( Date: Tue, 10 Aug 2021 11:44:20 +1000 Subject: [PATCH 05/76] Update Header.tsx (#6289) --- docs/components/Header.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/components/Header.tsx b/docs/components/Header.tsx index ea1adb65830..23839cc99d7 100644 --- a/docs/components/Header.tsx +++ b/docs/components/Header.tsx @@ -128,6 +128,9 @@ export function Header() { apiKey: '211e94c001e6b4c6744ae72fb252eaba', indexName: 'keystonejs', inputSelector: '#search-field', + algoliaOptions: { + facetFilters: ['tags:stable'], + }, }); } else if (searchAttempt >= 10) { // @ts-ignore From 3d4c2685c6a1c42246b6c7881e7fc46eae520c20 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Tue, 10 Aug 2021 12:00:17 +1000 Subject: [PATCH 06/76] Add CTA block for Web Box eCommerce Course (#6273) --- docs/components/content/AdvancedReactCta.tsx | 116 +++++++++++++++++++ docs/pages/why-keystone.tsx | 63 ++++++---- docs/public/assets/wesbos-cta.jpg | Bin 0 -> 106606 bytes 3 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 docs/components/content/AdvancedReactCta.tsx create mode 100644 docs/public/assets/wesbos-cta.jpg diff --git a/docs/components/content/AdvancedReactCta.tsx b/docs/components/content/AdvancedReactCta.tsx new file mode 100644 index 00000000000..0acce3af78a --- /dev/null +++ b/docs/components/content/AdvancedReactCta.tsx @@ -0,0 +1,116 @@ +/** @jsx jsx */ +import type { HTMLAttributes } from 'react'; +import { jsx } from '@emotion/react'; +import Image from 'next/image'; + +import wesBosCta from '../../public/assets/wesbos-cta.jpg'; + +import { useMediaQuery } from '../../lib/media'; +import { Button } from '../primitives/Button'; +import { Type } from '../primitives/Type'; +import { ArrowR } from '../icons/ArrowR'; +import { Tick } from '../icons/Tick'; +import { Section } from './Section'; + +export function AdvancedReactCta(props: HTMLAttributes) { + const mq = useMediaQuery(); + + return ( +
+
div': { + display: 'inline-grid !important', + justifyContent: 'center', + alignSelf: 'center', + }, + }} + > + Wes Bos Avatar +
+
+ + Learn Keystone for eCommerce with Wes Bos + + + Master eCommerce with Keystone, React, & GraphQL. Join Wes as he teaches you how to build + a full-stack online store with of today's best JavaScript technology. + +
    +
  • + + + 11 modules + +
  • +
  • + + + 70 videos + +
  • +
  • + + + 28,000 students + +
  • +
+
+ +
+
+
+ ); +} diff --git a/docs/pages/why-keystone.tsx b/docs/pages/why-keystone.tsx index bdba1d054b0..f4e07441955 100644 --- a/docs/pages/why-keystone.tsx +++ b/docs/pages/why-keystone.tsx @@ -14,6 +14,7 @@ import { Automated } from '../components/icons/Automated'; import { Migration } from '../components/icons/Migration'; import { Section } from '../components/content/Section'; import { Button } from '../components/primitives/Button'; +import { AdvancedReactCta } from '../components/content/AdvancedReactCta'; import { EndCta } from '../components/content/EndCta'; import { Emoji } from '../components/primitives/Emoji'; import { Updates } from '../components/icons/Updates'; @@ -89,7 +90,7 @@ export default function WhyKeystonePage() { margin: '1rem 0', }} > - TODO + Depiction of Keystone’s Admin UI
    -
  • - - eCommerce - - - Keystone gives you the power and control you need to build a complete backend for - eCommerce, while making it easy to integrate platforms like Shopify and Stripe to - get things done. API first, make Keystone a key player in your eCommerce content - mesh. - +
+ + +
+
+ + eCommerce + + + Keystone gives you the power and control you need to build a complete backend for + eCommerce, while making it easy to integrate platforms like Shopify and Stripe to get + things done. API first, make Keystone a key player in your eCommerce content mesh. + + + Try the eCommerce example → + +
+
+ + I use Keystone in my{' '} - Try the eCommerce example → - - - + Advanced React + {' '} + course because it’s super quick to get my content types up and running, add custom + server-side cart & checkout logic, and the fine grain access control is just + fantastic! + +
- {/*
TODO: WES BOS COURSE LINK...
*/} +
TgARNHQ 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∨&Dm;y&QRy}t{Ck*zZXcA$9|Kfz zaVx*w4Ez=VPTvZaf9ShJA}lZv*y|_`GDt(-2xenk{wlzic{_iIY~#ax1Qx%SWtKZy zS`QWbi=gII1u)yC?Q0mvxc6+ZuJ_Z=+RQ;Oa7VWNOCqs8JqQEQV(@npR z4zuYHXi22Q|3mcy=LibX;Ou3eh5}@<;t-bCX{(C~t3%NKV<4#|#x_2pieoSnPgW*t@1skPQ+yN0nC zF7ZaJwrPBw$62#^kYxDsn&nqY!a*cxC`v;tnz}}BU*Bq|C%BP6c+&pwTWs*Ox}?aw zXneR_>r=)po+D$xQHKj}-`gLs;y8??N85{RI{%xop9K>YxDozR2pvz5I1O1AE3kqW z#n>7~@>kl8jAo^8Rh3d~2c_ufxFN1~CatGR?jvv;MUgCb9H#^lA4{U zQ)^8}^Ns*Z&FvD6BAt4^;@ea9u-GW4M*o^~o(foj86i8{P+d@*_1rek)kuiON(Z1b zg3~t?y_cyOF^xwo7v#oM$A_(_UHHkT0T1lnNfW+}S&&VSN4GA&_<#WlUs`)@E_%C# zBnTf?Y&s(QYB)*8ay1L}&G`AtT#g-$-f#a3TqDf-sN`hsfU&Q#v4hUlFQ)j_9B@xYqXK=ov*>6I(D>0CnZnJ% ztCxbie?fBr>hwQ(4Bz%Owg#Rto?HHiWWbIfs*F{sWBL(u(>1;V!K7~YO({qTP<&{= z;0}ltLh~<`am0ET(nu2Jiz3hkv+UDJb(qmW&NAlK48{x}zK91$8pYfZ6&bX-^hojq z0ph+DA=RDy@Qr*o2HTcKW%%w;=pvzNjIl9}@3yoG-^AY&X>_$ea5GYra#-1gjT8B6 z^P}?I?4wHId02y0W*0>#+{7^GsihJ?FSK7$XE|(ntZH0bE7hfHyQpBqxa-p$(JrTn z-p@4yNPKl$b%_otUd)L)(YQVC{ZYxOezQSX>rK(LR1NZDDBJ|(5}fb@HrI8q>BHA< zknBNgbU8DRgn{QgjvV+^6_$*6c6E~!x_t=+z$QL}J0imo{+aR+2FST-TmgbpUij}{ zE-17!!QhvJ%erj{A1}%pZz)L^Q1zj&>_*p>d!g%&h&)GKnA2Bce*8sTzC!UHTAh=@ zrDE{HuIHNB9^Z3Ebjs`7Z-G%@u%tM(1{hn78S+#ycy>&erIod<-xfXs1u6{R5#h&A zLj3JRUvd@JrdICFw<<0FLH75aYllvs1-g}(dBz7~8w@J<$4<6#YkX0ev$K9vt*ER! zB7QzUfyqC-tAv!unEk`n3%)~gB~V#iBgi^jagLW457|WP{6MIlyBll6d__bhw<>BA zqd!h`!e3+tX0%P4AKC3@&0Z@5-4=gUuJ~~km?0$W#%ac{&hFi8D4YmNcSM}5&U5|N zh>jh!)x(dXWw&-@^aWA%et28qpzSxjy{_H_-y@a6!00Yj-w|X%Zjs?ZmZvbG9B;pk zI1%@VHRYq@TfrR_n10Jta0x9jolc%}7BKPXH#Z1{Wi(ro^@cJ;CSJVAT&3t3xg9s_ z9;lHE-3o~WXZT%bgt5czLQ1HG8NZx3h*USMTc2_$EEI6_BBt@VN`0YR-Z4f4o8%eqp zI$tz#RUN+j#@CDVIY^j~W(aGvqVnA}12MCQIjQ*R-*qgwh!VHLwnx`b!dGR+|i z$scUI5Vc_rhg=c3q{dz-Glr{>*qAZ^nb~|J8S-Mc3L(kszQvGQoj=`5D_zTo3l-!; zoW7*)JxhiYt|{u}@>lwp4@>ES%<`qUp~ALd#s|s2!^E!?j94#O%-X}K9^{;TD6rHb z=Ls$`@(fDvOk1mR{z-VzYCHytw(ii=LpLy&`tlm6oF0hQZ(B|f(rB9Qh;R-k0GO4& zv=ySl(S3Q0QIsd3Q9bP3vl^-M4c7eqjz~q^a}l%eH&x_;bL=#7KK5v1^pE{>tE=4{ zY^=Aop`xY$ax)ppH5cO>YsSFqrOsv3%ot!LiY8_`A{h#bk4JSvG*7uqA{xXEAEsLO z4|5sYI{NVy#a{Iq>n?XBaGJqbtiIWT^MxPkO9#*Xy13pwb=e2Ljn#K@rD3`Q`%~HFgYkm9h zNJ5ya7gff{oKl&heX9%$=kH8a%j6nMWr3yL6h*33XQ(2In}LE2*TH0NSylTfg^fzX zTp8Gf*4Hi1dy6CKQ0Z1tU%&TnA?AEt6^TE$>jt7+e}V<&V4T-U`m}j}7hrfAukIo> zfzeGnk63_?OTD;r;rHa9zZ5cJT}}ziGv=4HQ>K|{IW{a)Bs%_H2Q@D!Cm7d!L7Bc~ zxpO%9hft!4=fnjFuI0YS_K*zNCVkHXV*T#LOUt2>yxA=25I>_kP;6F0#-QC>(4m{& zFSKg?-`Y4(QeiZV^Tv|0$HRT>!UzXweO@bXQDuwzwijgx2F{LmefNRjVw&wTKHlnN zUa>}-5T=8}WD{#hZ@at%uz&YV}_T67LwkPz%IlJB0LXul)C~-TDx^ZZPF_ZXs z9(f>h`pErqv^lM}dG+q}N*!n;&#O6war))u2iaYptuuJg#DNyM`}1=&Ebk_btV;DW z&n_r_tdCl!336@OUk!LXHM2T0MjGYO)m*0ZXdZw{cYAcZLdl95?V*`2E+}!1ALV&f ze&`F|i}^Jf-OCh!6$s3riq(r0C@v{7HDoO7348s=li;nR+yUWps5xej);QnJH1CEV z#2(qBj3Vy6Xo4Tp)*C-Wt?T00;%u~xFjBT1DVB%81gls=qFdCM0Psl%dl@)PEHzbv zf%#eIiQ-rkU@}eo^&oVj@V_mj5xZ)Zscefx6*4*!xcqCIzvgHzxuM!6YO+yxM+bej zGzWxSQ9x~H(@SWYeQj;_0t3@Am4JZjYz%~UIiu@`ZP>AaVJGh$(eZHnVm<^Q{MkV% zaN;rU;;(9}>?KbfSNiP(bY@d>uiDUsTuDg)FQ{ic8gIDISY|SH!_enT5S+0mlD9nv_?>T{ns)zfpj5u}9`8$2X6e_;$9XC;UF& zU!=pd=2ReI9Dp|=hyQJtUnPS}{hjP;-(L7`gpKDuDYZ_`aAN=4n-w{sv9qQKUHup` zcrM!|JcV=~X=Ul+&$#%u!WE%GBIF7c{_k>JDeYFcLV9Cjs5H*_`+bLhF7X`^jh&Pd z6Kl+btIOdL=MBhftk&z7uhJ=4<4GwDZ~seA?~`I8^J*5XMK+92=@Y0Fn#C3_$jxzj zLCv33^OtK!B8+y#d(Y^{Dx~b`TsK@H^x-w&(qF(Q)IJp2Y|7i$U$|@ky8B6<*6xw8 z+~3RK>W2^MUY~Lwobuwqjup`=e=h4bZ0Yo_qAs?|Ccoc{rn2}*k*I$6z7l_(sA@gd zSru4vgRNDiy6t59n4e2+W`Pni)G~5#N_C)KijJ`8dI4<+%NmP8bv<5(Y(zZkd<2*88Y)!P<1}ZjwS3#45dj@R!+wbT zrG?=2yOkxD>}p;}IK*6+yX2jM_D9vc$7A)rp9{2y+(yXfRiOX!Ex=gJnX~Xbjqzuk z%9Bs#UKZ?P&|qWNM(|^*U-; zEPNzNMZi~()u+heQa`II=S&+!`1(hG(3IJyd;eF3!7=aI~cW->i6w%6wz?D@-dsnj#4y8xPda z$nF>!DTJ`xX4=h?@uSa@q7`@*CFjH{Bh{GcBmgB-y( zuJu$w*XMJK&iWHp3=M^69>=O87*mHWyR(j~oq?bb(lY15aJDMWedi_gIH!_mYmTRs z@VUr)zf#o7NJYs_mBwDp4)>J~bwcBuxg}-OHq6Dhu_RmRCu_~iuG>LyM)T@O=N*wK zJqP^K`jN8LMpO8{dL*bC>(Rr&5wa;f)EHy!lN$y9ifYB^eVu8$kVb>s89LQw)bn+` zYu#R!frS4O-fyj=gbaTNT*#yAXN%ek!FOb-?<*gwm+Irf-cyje`YU-w$fcC$EB=*5{5UXA z!pa)Z^eofwm<|;CmbdJVx7Xz&Bz`^pNoBWsq2v$LCYcW{HLZ8Q{j6n~PO5nRx$0Hn z$o9S)CUm;$X_8CFg}|(0Swp})(o%lx2(ImUxOVQ)V=&Ux*I7VfWGt*bi_DM-KFy`eX6w9k`~c@%iZdCGjaD1j4%O8Qa++T|aOyP}Le@L@bCP4E zHr{Yo9KHQ^$y>1H_IX=Mb1AZmT~q9@;H2L!cf(7x7z{kOmM&U9d$~X}t&>o*~8O zaIu1!*s3Z0WhEo@i&465I9u1f6lLrsqc_^~*#)$&Lcv|TKK6|+3BaIDoKnzogzlMR z>jHAlwv@o&V(#r(zOGYU3Y7~Cs`R}n9Od4>us*K&MBP>=Lfa2nyUlxUH($fI56;NA zP_Vz|6^H27XQM|HK-+^pf)eNIKsHmiwvG`A?%I<4&{JPS#-y5zp`?T*jVXgeJRoAX zp2579@r7%SwDXCE&U41WieX^rME>T;x-N&_qW5+1zW~KkEmlXwh-*lK`ma10(TY2w zScv11gITRYi$W}0dK=@u^YoY*D34v;0x6@m8CG%4AOdgB-(47wgtcqljO3ojl=U(9 zU8wI|2yTG$j)qXV_`VzX%W~JIf$673SC!)^OrZ4F)b@B+ccWEGCn1mNWU*PgwHA0EQ;YfP!zh=0^2~uzv#09T&?w*hlZ8PPm^ea@4LJyDdh@uo!2pt>^4k(fQu$GKHK$ljp}7f^+;+CbeJ@ zuC0np)Yb=owRKFnO81NQ%^I>gz$f83y>opTm2x&X9S|2|@{!7<^jRUh^jIJ;784bX z?%)i=Lhp!{M=EA)82m8J6rOJ~7^-g`p%M}OHE4}G^g(aN)L{2KEU9pM|2s_O$ed zB{}Al%IAvt1j57so>4Ank>R&`cDXea(bg>&{(M1{(2Cc1MH9wFJ#bu@Zf$GGj})ue ztunmBw6nt;_LAnDj&|4;68w+Z`EyU{H8`SU+85 z7y2uiOVH4osxBah&&<=UP3ir%85>{zh~?-)(LQ9Fu}2KvD>W2nQ(qX(zGo+%R?s+I z=j>L*L!fc+<-5lje&_Pua0Nin^JZp=IKBYhX*yqE=eDUX9H|E_J>{PPYn;qz6tF7e zZ_gY0;`=!k+1_~^$HmzhUnNUND3qFyI=m$Hhsp^-tg89)b%VLH81qI^n4W=iKE3AS z7!i?E6QpA$?JkE#T;v?+9*^v*qgxNAEe>G0(35qgPSc*d# zJ8)!q^Oc8~j?AkH$sfd2owFeTD*4rp<}97RY_XW;C;szj#glYj-Qs-xh(lJftj2gg zBY4PTymMKkwa?C=07S2SEZsz(XUx9Wl1$1GIZQpR5NB5*`6j7wh9|B;tQYihLf1^` z*K9#STeiu4i32Hlo%Wd0EE!iiP@UsP-a-1V!q>}|wtJWhHw(Ru&>ioKOY%|~&5gL- zcJT{ja(9RJNaLe!9%dRta;S{c1bq#0YN8kfR&L*lz59{d4X&boJ^RxK9^6}V6_^Fi zhZkVhHGJkP<>*CSHR8Zo%9K-4kf*3JX-az*E|pnZQjW;{u@zcsql;JzOkY&GW<`|q zA>dYYKv9_zri|02%LisHBFJ-3JL9#n*qKb|a$R;zS_9il_!W&OrJ8Cxy>vZVZwlV* z@1xLH^Vo#5%~cw*$bQE51M`uI7ftW-T~6vmQud__<& zLxV|BRKv~g?E}(3Zo{DX6*`GDgAOgU=N8Y2H?ZzfykM0YMl;ph)AP9*Qt@@8&576d zt3FGT{ZPSYY|*|}Y;*=eyT)T84fSO#}woJ{CFeNw65iLk0qDmUX;+4AF9hL~48#7n?Cl3DHjb z+gsQ@9gr~MA5z7-ZlDGQq{{;us_6my&omeARFq2 zscGl1&0K#)Rm8AKAs7V~JGIS^k+mrl3z)TW<c($Um z(%aK#XtQ*qE8I|FR<(Oe-L9*CE`J~xn+dJma=D(UMC|UzmZguJun=H=Y(WPKr*g}z z!pGLjY~@sA0)tXLnA(rBr|gpBny9xmIS2Zf(wufxZUn;B;?Gz!TcCl&vcO`7TxG5V z9^gTvQw9e}PT>M{KfE|Zq2w5Fpw&Di79JK(PipDfC~C{6v&c*#facaBB{VvOijnESB$3KTWqvh&ya*IM zrIB0rhn%etoTd0s*p9PwJ1DD`?nGi+y+aR~<1WzXr%>?I!Vn^{Y!K%&t1@Sq*+p8{ z*Ye6>9_XFyqT+UpEFRV04j3Cw=wGKz8@I}*h%~PzEfG|VY^8HfVcJC(Fj+JnnVbgCw z;mzcgZkX~T-l?wgL$`YIu%DKla3yhboI^$UhnVfoK1TobswCY%zDBTNLoI)Mp=NQu zoUHDrpK<*)8JN_)w(C4eono)~`(uT&7Dzxb*E(~mR8?th9r}ppr_jI7Zuw|sOj&DW zUNGZgBv$rs)u>K4hZy`sA}A(E^6O3 zRRZq_p$1H$5DZU;c6cX&+u(pyfm^ z=@lyvJ8~juP{L1Aa0)Z?2Qz02Iu)v%pG(IQPr8%3;J2al|W}s zXm)EJBddn*ImG$;Yr_9Ebrm8gYOsvfJ9jOR{RVB;^xqB2b za|Ct(|NiY?)Ctsq`#d=7>ms@J^Rg}HHxl1d_JRHA0R0kOtM0;(TeHpj6Af> z`ZgDbL|P&u6N<|xuWpUpmlm#NJvZuQGmroy$vqJ0p9wu(Ec%K)frQ+$N* z!_s(GBXy6%o>2Q?H|$qatAT-1crPNMDY~uZNwul{;+SkYU*#~o?$Y$P$f|(@>M1tE z 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 L5RW7M+kgMr>Dx4L literal 0 HcmV?d00001 From f97a9ca31aef2ff20ac4b255cf4d21803a4affd5 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Tue, 10 Aug 2021 12:09:25 +1000 Subject: [PATCH 07/76] Content update (#6290) --- docs/components/Page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/components/Page.tsx b/docs/components/Page.tsx index c56ed0c3796..9c896ac8f5c 100644 --- a/docs/components/Page.tsx +++ b/docs/components/Page.tsx @@ -18,8 +18,8 @@ import { Footer } from './Footer'; function Announcement() { return ( - Keystone 6 is in Community Preview! What does that mean? see our{' '} - Roadmap. For Keystone 5 docs, visit{' '} + Keystone 6 is in Community Preview! For Keystone 5 docs + visit{' '} v5.keystonejs.com From 2963ac79345386637e41821700ce0185d42cbc79 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Tue, 10 Aug 2021 13:20:00 +1000 Subject: [PATCH 08/76] Style fixes (#6291) * Fix styles: CommunityCta * Fix Styles: Homepage * Stylefix: Wes CTA block * Style fixes: Why Keystone * Style fixes: Content Management * Style fixes: Developers * Style fixes: Organisations * Style fixes: Prose lite Reverts text color to default `--text` var per Figma * Style fixes: Docs Home * Stye fixes: examples CTA --- docs/components/content/AdvancedReactCta.tsx | 6 +- docs/components/content/CommunityCta.tsx | 10 +- docs/components/docs/ExamplesList.tsx | 3 +- docs/components/docs/GitHubExamplesCTA.tsx | 2 + docs/lib/prose-lite.ts | 1 - docs/pages/for-content-management.tsx | 36 ++-- docs/pages/for-developers.tsx | 48 +++-- docs/pages/for-organisations.tsx | 25 ++- docs/pages/index.tsx | 65 ++++--- docs/pages/why-keystone.tsx | 192 ++++++++++++------- 10 files changed, 240 insertions(+), 148 deletions(-) diff --git a/docs/components/content/AdvancedReactCta.tsx b/docs/components/content/AdvancedReactCta.tsx index 0acce3af78a..96071599b91 100644 --- a/docs/components/content/AdvancedReactCta.tsx +++ b/docs/components/content/AdvancedReactCta.tsx @@ -81,19 +81,19 @@ export function AdvancedReactCta(props: HTMLAttributes) { >
  • - + 11 modules
  • - + 70 videos
  • - + 28,000 students
  • diff --git a/docs/components/content/CommunityCta.tsx b/docs/components/content/CommunityCta.tsx index a710fe40464..dfb2001721c 100644 --- a/docs/components/content/CommunityCta.tsx +++ b/docs/components/content/CommunityCta.tsx @@ -54,7 +54,7 @@ export function CommunityCta(props: HTMLAttributes) { Learn with others in a supportive community - + Share your work and get the help you need in the Keystone community Slack: an inclusive space to share ideas and explore what‘s possible. @@ -88,11 +88,15 @@ export function CommunityCta(props: HTMLAttributes) { >
  • - 2000+ members + + 2000+ members +
  • - Personalised support + + Personalised support +
  • diff --git a/docs/components/docs/ExamplesList.tsx b/docs/components/docs/ExamplesList.tsx index 00c7cb14ec8..ec56892d60e 100644 --- a/docs/components/docs/ExamplesList.tsx +++ b/docs/components/docs/ExamplesList.tsx @@ -124,6 +124,7 @@ export function Examples() { users rate items on a 5-star scale. Builds on the Blog starter project. diff --git a/docs/components/docs/GitHubExamplesCTA.tsx b/docs/components/docs/GitHubExamplesCTA.tsx index 28401fa9fdb..9f1d6c700ad 100644 --- a/docs/components/docs/GitHubExamplesCTA.tsx +++ b/docs/components/docs/GitHubExamplesCTA.tsx @@ -18,6 +18,8 @@ export function GitHubExamplesCTA() { - - Read the guide → - + + + Read the guide → + + Working with @KeystoneJS is such a pleasant experience. After hand rolling a few GraphQL @@ -188,9 +190,11 @@ export default function ForDevelopers() { configurable CMS built in. Program with JavaScript, store changes in version control, and integrate with your preferred CI tools.
    - - Keystone for content management → - + + + Keystone for content management → + +
    - - Access control API → - + + + Access control API → + +
  • @@ -305,9 +313,11 @@ export default function ForDevelopers() { One to one. One to many. Many to many. Self-referential. It's all there. - - Relationships guide → - + + + Relationships guide → + +
  • @@ -318,9 +328,11 @@ export default function ForDevelopers() { Kick start new projects and try examples on for size from the comfort of your terminal. - - CLI guide → - + + + CLI guide → + +
  • diff --git a/docs/pages/for-organisations.tsx b/docs/pages/for-organisations.tsx index 8646bd10488..3005c719989 100644 --- a/docs/pages/for-organisations.tsx +++ b/docs/pages/for-organisations.tsx @@ -109,12 +109,16 @@ export default function ForOrganisations() {
  • - - Keystone for developers → - - - Keystone for content management → - + + + Keystone for developers → + + + + + Keystone for content management → + +
    Working with @KeystoneJS is such a pleasant experience. After hand rolling a few GraphQL @@ -210,6 +216,7 @@ export default function ForOrganisations() { Batteries included. No limitations. - + Ship a backend easily without surrendering control.
    Keystone has all you need to start fast and scale on your terms. @@ -221,61 +221,61 @@ export default function IndexPage() { >
  • - + All the field types
  • - + Access Control
  • - + Session Management
  • - + Custom Schema
  • - + Database Migrations
  • - + TypeScript Support
  • - + Powerful Filters
  • - + Relational Data
  • - + Automated CRUD
  • - + Event Hooks
  • @@ -289,7 +289,7 @@ export default function IndexPage() { How it works - + Enable a content culture that’s productive, collaborative, and fun.
    Open, flexible, and natural. A tool your team can grow with. @@ -377,7 +377,7 @@ export default function IndexPage() { Rapidly spec your backend with all the primitive and advanced field types you need. - + Add logic, access control, and custom queries & mutations to create an API that's unique to your app. @@ -662,6 +662,7 @@ export const lists = createSchema({ Unify your team dynamic - + Enable a content culture that’s productive, collaborative, and fun. Open, flexible, and natural. A tool your team can grow with. @@ -784,40 +791,46 @@ export const lists = createSchema({ Developers - + Backend superpowers for frontend devs. Built the way you’d want it made, Keystone is at home with the tools you know and love. - - Keystone for Developers → - + + + Keystone for Developers → + +
  • Content people - + Get the fields, forms, and workflows you need to do your best work. Tell the full story with a rich text editor that can be configured for any content need. - - Keystone for Content Management → - + + + Keystone for Content Management → + +
  • Organisations - + Realise your vision with a backend you can shape to fit your logic. Own your data, cultivate a productive content culture, send your message anywhere, and scale on your terms. - - Keystone for Organisations → - + + + Keystone for Organisations → + +
  • diff --git a/docs/pages/why-keystone.tsx b/docs/pages/why-keystone.tsx index f4e07441955..0df59cc52c1 100644 --- a/docs/pages/why-keystone.tsx +++ b/docs/pages/why-keystone.tsx @@ -173,7 +173,13 @@ export default function WhyKeystonePage() { What’s in the box? - + Everything you need to start fast and scale sustainably. We’ve done the heavy lifting so you can work on what matters without getting boxed in. @@ -200,9 +206,11 @@ export default function WhyKeystonePage() { Out of the box data ops for every field type. A powerful GraphQL API from day one. - - Access control API → - + + + Access control API → + +
  • @@ -213,13 +221,15 @@ export default function WhyKeystonePage() { Extend the CRUD API for more control over what you do. Customise it to your frontend needs. - - Try the example → - + + + Try the example → + +
  • @@ -230,9 +240,11 @@ export default function WhyKeystonePage() { Highly configurable. Design systems friendly. BYO custom React components. Structured JSON output. - - Try the editor → - + + + Try the editor → + +
  • @@ -242,9 +254,11 @@ export default function WhyKeystonePage() { Start and end sessions from the GraphQL API. Secure your data using access control. - - Session API → - + + + Session API → + +
  • @@ -265,9 +279,11 @@ export default function WhyKeystonePage() { Build your own roles-based access controls. No limits on the amount and kind of roles you can configure. - - Access Control API → - + + + Access Control API → + +
  • @@ -277,9 +293,11 @@ export default function WhyKeystonePage() { One to one. One to many. Many to many. Self referential. It’s all there. - - Relationships guide → - + + + Relationships guide → + +
  • @@ -289,9 +307,11 @@ export default function WhyKeystonePage() { Find what you need when you need it with intuitive filters. - - Query Filters guide → - + + + Query Filters guide → + +
  • @@ -311,9 +331,11 @@ export default function WhyKeystonePage() { An editing environment you can shape to the needs of any project. No boilerplate. Everything as you make it. - - Fields API → - + + + Fields API → + +
  • @@ -324,9 +346,11 @@ export default function WhyKeystonePage() { Put custom logic in your data ops. Modify data, trigger events, validate inputs – it’s up to you. - - Hooks guide → - + + + Hooks guide → + +
  • @@ -337,9 +361,11 @@ export default function WhyKeystonePage() { Kickstart new projects and try examples on for size from the comfort of your terminal. - - CLI guide → - + + + CLI guide → + +
  • @@ -362,7 +388,13 @@ export default function WhyKeystonePage() { What will you build? - + Naturally, it’s up to you. Here’s some things we've used Keystone for:
      Apps - + A programmable backend you can rely on for Web and Native apps of all sizes. Start with Keystone’s built-in features then add your own, and integrate 3rd-party systems or microservices. - + You can control data input exclusively from your frontend, or use Keystone’s intuitive and customisable CMS when you need it. - - Try the Task Manager example → - + + + Try the Task Manager example → + +
    • Websites - + From simple blog, to complex multi-brand site networks, Keystone’s the backend fit for modern web experiences. It’s a CMS that ships with no hard opinions, so you can build the fields and types you actually need. And a WYSIWIG you can plug custom components into, that outputs structured JSON. - + Give your content people the tools they need to do their best work. - - Try the Blog example → - + + + Try the Blog example → + +
    @@ -437,18 +473,20 @@ export default function WhyKeystonePage() { eCommerce - + Keystone gives you the power and control you need to build a complete backend for eCommerce, while making it easy to integrate platforms like Shopify and Stripe to get things done. API first, make Keystone a key player in your eCommerce content mesh. - - Try the eCommerce example → - + + + Try the eCommerce example → + +
    @@ -530,40 +568,46 @@ export default function WhyKeystonePage() { Developers - + Backend superpowers for frontend devs. Built the way you’d want it made, Keystone is at home with the tools you know and love. - - Keystone for Developers → - + + + Keystone for Developers → + +
  • Content people - + Get the fields, forms, and workflows you need to do your best work. Tell the full story with a rich text editor that can be configured for any content need. - - Keystone for Content Management → - + + + Keystone for Content Management → + +
  • Organisations - + Realise your vision with a backend you can shape to fit your logic. Own your data, cultivate a productive content culture, send your message anywhere, and scale on your terms. - - Keystone for Organisations → - + + + Keystone for Organisations → + +
  • From d534409e32759439beae1a654dc930702d41f3df Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Thu, 12 Aug 2021 08:11:32 +1000 Subject: [PATCH 09/76] Added new content to /updates (#6300) --- docs/pages/updates/index.tsx | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index a26302df2fd..92518a0fdd8 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -165,7 +165,32 @@ export default function WhatsNew() { gap: 0, })} > - + + + We're opening Admin UI up to support a more personal content experience. Now you can: + + To deliver a more productive editor experience that's aligned with the needs and brand of + your organisation. + + + + We've added an optional /_healthcheck endpoint to Keystone's + express server. Use it to ensure your Keystone instance is up and running with website + monitoring solutions. + +
    Date: Fri, 13 Aug 2021 09:28:37 +1000 Subject: [PATCH 10/76] Update fields.mdx (#6304) --- docs/pages/docs/apis/fields.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index 38b26c6e6a4..88d5c0ef067 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -458,7 +458,7 @@ Read our [relationships guide](../guides/relationships) for details on Keystone - `ref` (required): A string of the form `` or `.`. - `many` (default: `false`): Configures the cardinality of the relationship. -- `defaultValue` (default: `undefined`): Can be either a relationship input value or an async function which takes an argument `({ context, originalInput })` and returns a relationship input value. +- `defaultValue` (default: `undefined`): Can be either a relationship input value `{ connect: { id: ID } }` or an async function which takes an argument `({ context, originalInput })` and returns a relationship input value. This value will be used for the field when creating items if no explicit value is set. `context` is a [`KeystoneContext`](./context) object. `originalInput` is an object containing the data passed in to the `create` mutation. From e29b5e4f79eaaad1bb04cbb5ceee40fccdb79023 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Mon, 16 Aug 2021 09:30:43 +1000 Subject: [PATCH 11/76] Fixed typo (#6322) --- docs/pages/docs/guides/hooks.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/docs/guides/hooks.mdx b/docs/pages/docs/guides/hooks.mdx index f343cbd2cfb..404eeaf1eec 100644 --- a/docs/pages/docs/guides/hooks.mdx +++ b/docs/pages/docs/guides/hooks.mdx @@ -157,7 +157,7 @@ export default config({ }, hooks: { afterChange: ({ operation, updatedItem }) => { - if (operation === 'create) { + if (operation === 'create') { sendWelcomeEmail(updatedItem.name, updatedItem.email); } } From 64e6c1daf9251cc2f2f4da26007b2805d139ed50 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Mon, 16 Aug 2021 11:10:45 +1000 Subject: [PATCH 12/76] Added top margin to docs page component (#6301) --- docs/components/Page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/components/Page.tsx b/docs/components/Page.tsx index 9c896ac8f5c..85d0848561b 100644 --- a/docs/components/Page.tsx +++ b/docs/components/Page.tsx @@ -100,6 +100,7 @@ export function DocsPage({ Date: Mon, 16 Aug 2021 12:39:49 +1000 Subject: [PATCH 13/76] Added styles to table (#6315) * Added styles to table * Update prose-lite.ts * Update prose-lite.ts * Update prose-lite.ts Co-authored-by: Thomas Walker --- docs/lib/prose-lite.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/lib/prose-lite.ts b/docs/lib/prose-lite.ts index bbe636e4cd3..d96b0595a7c 100644 --- a/docs/lib/prose-lite.ts +++ b/docs/lib/prose-lite.ts @@ -153,6 +153,9 @@ export const proseStyles = { marginBottom: '2rem', fontSize: 'var(--font-xsmall)', lineHeight: 1.7142857, + maxWidth: '100%', + overflowX: 'auto' as const, + display: 'block', }, thead: { color: 'var(--text)', @@ -173,6 +176,9 @@ export const proseStyles = { paddingRight: '0.5714285714em', paddingBottom: '0.5714285714em', paddingLeft: '0.5714285714em', + '> code': { + whiteSpace: 'nowrap' as const, + }, }, fontSize: 'var(--font-small)', lineHeight: 1.75, From 4427bbccc193740cfb386a36cf887c527634a398 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Mon, 16 Aug 2021 15:48:11 +1000 Subject: [PATCH 14/76] Un-nest tags. (#6327) --- docs/components/Page.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/components/Page.tsx b/docs/components/Page.tsx index 85d0848561b..b0fe1ae53b8 100644 --- a/docs/components/Page.tsx +++ b/docs/components/Page.tsx @@ -41,7 +41,7 @@ function OpenGraph({ ogImage = `${siteUrl}/og-image-landscape.png`; } return ( - + {title} @@ -53,7 +53,7 @@ function OpenGraph({ - + ); } @@ -85,9 +85,7 @@ export function DocsPage({ return ( - - - +
    - - - +
    Date: Mon, 16 Aug 2021 17:13:57 +1000 Subject: [PATCH 15/76] Fixed link value (#6328) --- docs/pages/docs/guides/hooks.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/docs/guides/hooks.mdx b/docs/pages/docs/guides/hooks.mdx index 404eeaf1eec..b76871e50a1 100644 --- a/docs/pages/docs/guides/hooks.mdx +++ b/docs/pages/docs/guides/hooks.mdx @@ -220,6 +220,6 @@ export default config({ }); ``` -See the [fields API](../apis/hooks) for the details of all the arguments available for all the different hook functions. +See the [Hooks API](../apis/hooks) for the details of all the arguments available for all the different hook functions. export default ({ children }) => {children}; From 36f6550dba2de045fec4d0433d401dcfcd9c8611 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Tue, 17 Aug 2021 11:11:13 +1000 Subject: [PATCH 16/76] Update `website_live` (#6336) * Update patch dependencies (patch) (#6253) * Update search config to match new DocSearch config (#6255) * Update dependency/apollo client (#6259) * update apolloclient dependency to latest * changeset * Update dependency @graphql-tools/merge to v7 (#6246) Co-authored-by: Renovate Bot * Rename first to take (#6266) * Expose stacktraces from exceptions thrown in before/after hooks. (#6263) * 6268/next typescript config error (#6269) * add typescript ignoreBuildErrors flag * changeset * Updated /updates with new things (#6272) * Check exceptions returned from GraphQL (#6271) * Lock file maintenance (#6277) * Allow bearer auth in header using sessionToken (#6276) * Use Next 11 in the website (#6256) * 6223/custom pages guide improvements (#6264) * update example to include helper components * update docs and examples * update docs and examples * update to docs * more updates * changeset * correct incorrect props in README.md * update smoke test * update images * update example * update tests * remove next dep from package.json * updates * re-add schema.prisma for admin-ui-navigation example * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Apply suggestions from code review Co-authored-by: Tim Leslie * update docs * revert change to next-env.d.ts * Apply suggestions from code review Co-authored-by: Tim Leslie Co-authored-by: Tim Leslie * Update dependency eslint-plugin-import to ^2.24.0 (#6285) Co-authored-by: Renovate Bot * Fix updates bit on the website (#6288) * Include stacktrace flag (#6267) * Remove `gqlType` option on `autoIncrement` field type (#6280) * Use playwright install-deps (#6294) * Update patch dependencies (patch) (#6284) * Update prisma monorepo to v2.29.0 (minor) (#6292) * Nested filters (#6095) * GraphQL API docs changes (#6297) * Update dependency @types/jest to v27 (#6293) * Ignore generated files in prisma-utils (#6305) * Move import of mergeSchemas (#6310) * Update resolveInput error handling (#6316) * Upgrade Next to 11.1.0 for the website (#6311) * Update @graphql-ts/schema (#6312) * Lock file maintenance (#6320) * Split create/update field input resolvers for relationship fields (#6317) * Expand editable area (#6318) * POC - Expand editable area * Change things * Create cyan-rabbits-look.md Co-authored-by: mitchellhamilton * Fixed import url on CustomNavigation component (#6308) Co-authored-by: Tim Leslie * Update text filter API table (#6330) * Update the tags in the docs navigation (#6329) * Update patch dependencies (patch) (#6331) * Add a GraphQL API upgrade guide (#6281) * Fix issue with VisuallyHidden checkbox interactions in table (#6334) * resolve CHROME BUG * changeset * 6261/fix delete alert (#6296) * refactor confirm procedure to only add success toast on success * new deletion logic in Listview * add crud-notifications test project * update deletion solution to be more pragmatic at scale * update bug fix to be more verbose * update schema.graphql * minor updates * fix yarn lint:examples to not break when running more than one test-project * minor updates to copy * remove log * changeset Co-authored-by: Tim Leslie * Version Packages (#6199) Co-authored-by: github-actions[bot] Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Mitchell Hamilton Co-authored-by: Tim Leslie Co-authored-by: Ronald Aveling Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] --- .changeset/brown-glasses-complain.md | 7 - .changeset/chilled-grapes-cry.md | 7 - .changeset/cold-cycles-cry.md | 6 - .changeset/dull-humans-yell.md | 8 - .changeset/early-experts-allow.md | 7 - .changeset/eleven-mayflies-kneel.md | 6 - .changeset/empty-baboons-unite.md | 5 - .changeset/fast-guests-tickle.md | 5 - .changeset/fluffy-coins-argue.md | 6 - .changeset/good-cycles-ring.md | 5 - .changeset/happy-seals-cheat.md | 5 - .changeset/khaki-ducks-poke.md | 5 - .changeset/lovely-pears-sort.md | 7 - .changeset/nasty-windows-study.md | 21 - .changeset/olive-maps-serve.md | 5 - .changeset/olive-poems-explode.md | 5 - .changeset/proud-impalas-flash.md | 5 - .changeset/rich-tomatoes-own.md | 22 - .changeset/silly-impalas-type.md | 5 - .changeset/smooth-moose-eat.md | 5 - .changeset/strange-crabs-glow.md | 12 - .changeset/tidy-suits-refuse.md | 5 - .changeset/tough-geese-trade.md | 5 - .changeset/wet-frogs-share.md | 22 - .changeset/wise-pianos-flash.md | 8 - .github/workflows/tests.yml | 8 +- .prettierignore | 1 + design-system/packages/button/package.json | 4 +- design-system/packages/core/package.json | 6 +- design-system/packages/fields/package.json | 4 +- design-system/packages/icons/package.json | 4 +- design-system/packages/loading/package.json | 4 +- design-system/packages/modals/package.json | 4 +- design-system/packages/notice/CHANGELOG.md | 6 + design-system/packages/notice/package.json | 6 +- design-system/packages/options/package.json | 2 +- design-system/packages/pill/package.json | 2 +- design-system/packages/popover/package.json | 6 +- .../packages/segmented-control/CHANGELOG.md | 6 + .../packages/segmented-control/package.json | 6 +- design-system/packages/toast/CHANGELOG.md | 6 + design-system/packages/toast/package.json | 6 +- design-system/packages/tooltip/package.json | 2 +- design-system/website/package.json | 4 +- docs/CHANGELOG.md | 7 + docs/babel.config.js | 1 + docs/components/docs/Navigation.tsx | 32 +- docs/next-env.d.ts | 2 + docs/next.config.js | 6 +- docs/package.json | 17 +- docs/pages/docs/apis/access-control.mdx | 2 +- docs/pages/docs/apis/auth.mdx | 12 +- docs/pages/docs/apis/config.mdx | 11 +- docs/pages/docs/apis/db-items.mdx | 44 +- docs/pages/docs/apis/filters.mdx | 154 +- docs/pages/docs/apis/graphql.mdx | 358 ++-- docs/pages/docs/apis/list-items.mdx | 44 +- docs/pages/docs/apis/schema.mdx | 2 - .../guides/custom-admin-ui-navigation.mdx | 2 +- .../docs/guides/custom-admin-ui-pages.mdx | 159 +- docs/pages/docs/guides/custom-fields.mdx | 17 +- docs/pages/docs/guides/document-fields.mdx | 8 +- docs/pages/docs/guides/filters.mdx | 56 +- docs/pages/docs/guides/hooks.mdx | 4 +- docs/pages/docs/guides/relationships.mdx | 12 +- docs/pages/docs/guides/testing.mdx | 6 +- docs/pages/docs/guides/virtual-fields.mdx | 10 +- docs/pages/ds.tsx | 4 +- docs/pages/index.tsx | 6 +- docs/pages/updates/new-graphql-api.mdx | 405 +++++ .../custom-page-completed.png | Bin 0 -> 38028 bytes .../custom-page-w-page-container.png | Bin 0 -> 30913 bytes .../custom-page-with-styled-header.png | Bin 0 -> 34145 bytes .../custom-admin-ui-pages/header-prop.png | Bin 0 -> 9690 bytes .../simple-custom-page.png | Bin 0 -> 30570 bytes examples-staging/assets-cloud/CHANGELOG.md | 8 + examples-staging/assets-cloud/package.json | 6 +- examples-staging/assets-cloud/schema.graphql | 136 +- examples-staging/assets-local/CHANGELOG.md | 8 + examples-staging/assets-local/package.json | 6 +- examples-staging/assets-local/schema.graphql | 136 +- examples-staging/auth/CHANGELOG.md | 11 + examples-staging/auth/package.json | 8 +- examples-staging/auth/schema.graphql | 175 +- examples-staging/basic/CHANGELOG.md | 13 + examples-staging/basic/package.json | 17 +- examples-staging/basic/schema.graphql | 320 ++-- examples-staging/basic/schema.ts | 2 +- examples-staging/ecommerce/CHANGELOG.md | 15 + examples-staging/ecommerce/access.ts | 10 +- .../ecommerce/mutations/addToCart.ts | 2 +- examples-staging/ecommerce/package.json | 24 +- examples-staging/ecommerce/schema.graphql | 654 +++---- .../ecommerce/tests/mutations.test.ts | 4 +- examples-staging/embedded-nextjs/CHANGELOG.md | 8 + examples-staging/embedded-nextjs/package.json | 6 +- .../embedded-nextjs/schema.graphql | 72 +- .../graphql-api-endpoint/CHANGELOG.md | 12 + .../graphql-api-endpoint/package.json | 12 +- .../graphql-api-endpoint/schema.graphql | 344 ++-- examples-staging/playground/CHANGELOG.md | 8 + examples-staging/playground/package.json | 6 +- examples-staging/playground/schema.graphql | 58 +- examples-staging/roles/CHANGELOG.md | 12 + examples-staging/roles/access.ts | 14 +- examples-staging/roles/package.json | 10 +- examples-staging/roles/schema.graphql | 284 +-- examples-staging/sandbox/CHANGELOG.md | 9 + examples-staging/sandbox/package.json | 8 +- examples-staging/sandbox/schema.graphql | 167 +- examples/blog/CHANGELOG.md | 8 + examples/blog/package.json | 6 +- examples/blog/schema.graphql | 136 +- examples/custom-admin-ui-logo/CHANGELOG.md | 9 + examples/custom-admin-ui-logo/package.json | 8 +- examples/custom-admin-ui-logo/schema.graphql | 130 +- .../custom-admin-ui-navigation/CHANGELOG.md | 13 + .../custom-admin-ui-navigation/package.json | 8 +- .../custom-admin-ui-navigation/schema.graphql | 130 +- examples/custom-admin-ui-pages/CHANGELOG.md | 15 + examples/custom-admin-ui-pages/README.md | 42 +- .../admin/components/CustomNavigation.tsx | 17 + .../custom-admin-ui-pages/admin/config.ts | 5 + .../admin/pages/custom-page.tsx | 39 +- examples/custom-admin-ui-pages/package.json | 9 +- examples/custom-admin-ui-pages/schema.graphql | 130 +- examples/custom-field-view/CHANGELOG.md | 9 + examples/custom-field-view/package.json | 8 +- examples/custom-field-view/schema.graphql | 130 +- examples/custom-field/CHANGELOG.md | 9 + examples/custom-field/package.json | 8 +- examples/custom-field/schema.graphql | 144 +- examples/default-values/CHANGELOG.md | 8 + examples/default-values/package.json | 6 +- examples/default-values/schema.graphql | 130 +- examples/default-values/schema.ts | 2 +- examples/document-field/CHANGELOG.md | 9 + examples/document-field/package.json | 8 +- examples/document-field/schema.graphql | 136 +- examples/extend-graphql-schema/CHANGELOG.md | 10 + examples/extend-graphql-schema/README.md | 2 +- .../extend-graphql-schema/custom-schema.ts | 8 +- examples/extend-graphql-schema/package.json | 6 +- examples/extend-graphql-schema/schema.graphql | 208 ++- examples/json/CHANGELOG.md | 8 + examples/json/package.json | 6 +- examples/json/schema.graphql | 98 +- examples/task-manager/CHANGELOG.md | 8 + examples/task-manager/package.json | 6 +- examples/task-manager/schema.graphql | 130 +- examples/testing/CHANGELOG.md | 15 + examples/testing/package.json | 18 +- examples/testing/schema.graphql | 251 +-- examples/virtual-field/CHANGELOG.md | 9 + examples/virtual-field/README.md | 2 +- examples/virtual-field/package.json | 8 +- examples/virtual-field/schema.graphql | 136 +- examples/virtual-field/schema.ts | 2 +- examples/with-auth/CHANGELOG.md | 11 + examples/with-auth/package.json | 8 +- examples/with-auth/schema.graphql | 251 +-- package.json | 28 +- packages/admin-ui-utils/CHANGELOG.md | 7 + packages/admin-ui-utils/package.json | 8 +- packages/auth/CHANGELOG.md | 31 + packages/auth/package.json | 18 +- packages/auth/src/schema.ts | 2 +- packages/cloudinary/CHANGELOG.md | 8 + packages/cloudinary/package.json | 10 +- packages/fields-document/CHANGELOG.md | 35 + packages/fields-document/package.json | 14 +- .../src/DocumentEditor/index.tsx | 31 +- .../fields-document/src/relationship-data.tsx | 2 +- packages/fields/CHANGELOG.md | 117 ++ packages/fields/package.json | 18 +- packages/fields/src/tests/test-fixtures.ts | 32 +- .../fields/src/types/autoIncrement/index.ts | 91 +- .../autoIncrement/tests/test-fixtures.ts | 115 +- packages/fields/src/types/checkbox/index.ts | 5 + .../fields/src/types/checkbox/views/index.tsx | 5 +- packages/fields/src/types/decimal/index.ts | 5 + .../fields/src/types/decimal/views/index.tsx | 16 +- packages/fields/src/types/float/index.ts | 5 + .../fields/src/types/float/views/index.tsx | 16 +- packages/fields/src/types/integer/index.ts | 5 + .../fields/src/types/integer/views/index.tsx | 16 +- packages/fields/src/types/password/index.ts | 21 + .../fields/src/types/password/views/index.tsx | 4 +- .../fields/src/types/relationship/index.ts | 12 + .../relationship/tests/implementation.test.ts | 4 +- .../relationship/views/RelationshipSelect.tsx | 16 +- packages/fields/src/types/select/index.ts | 13 + .../fields/src/types/select/views/index.tsx | 28 +- packages/fields/src/types/text/index.ts | 10 +- .../fields/src/types/text/views/index.tsx | 23 +- packages/fields/src/types/timestamp/index.ts | 5 + packages/keystone/CHANGELOG.md | 165 ++ packages/keystone/package.json | 32 +- .../admin-ui/id-field-view.tsx | 13 +- .../admin-ui/next-config.ts | 3 + .../admin-ui/pages/ItemPage/index.tsx | 14 +- .../admin-ui/pages/ListPage/index.tsx | 102 +- .../next-graphql.ts | 2 +- .../src/admin-ui/system/getAdminMetaSchema.ts | 13 +- .../keystone/src/admin-ui/templates/api.ts | 2 +- .../keystone/src/lib/core/graphql-errors.ts | 11 +- .../src/lib/core/mutations/access-control.ts | 6 +- .../src/lib/core/mutations/create-update.ts | 64 +- .../keystone/src/lib/core/mutations/hooks.ts | 11 +- .../src/lib/core/queries/resolvers.ts | 24 +- .../keystone/src/lib/core/types-for-lists.ts | 45 +- .../keystone/src/lib/core/where-inputs.ts | 82 +- packages/keystone/src/lib/id-field.ts | 63 + .../src/lib/server/createApolloServer.ts | 44 +- .../src/lib/server/createExpressServer.ts | 16 +- packages/keystone/src/schema/schema.ts | 2 +- .../__snapshots__/artifacts.test.ts.snap | 66 +- .../keystone/src/scripts/tests/build.test.ts | 2 +- .../fixtures/basic-project/schema.graphql | 58 +- packages/keystone/src/session/index.ts | 9 +- packages/session-store-redis/package.json | 2 +- packages/testing/CHANGELOG.md | 7 + packages/testing/package.json | 6 +- packages/types/CHANGELOG.md | 126 ++ packages/types/package.json | 7 +- packages/types/src/config/index.ts | 34 + packages/types/src/filters/enum-filter.ts | 76 + packages/types/src/filters/index.ts | 88 + .../types/src/filters/providers/postgresql.ts | 647 +++++++ .../types/src/filters/providers/sqlite.ts | 438 +++++ packages/types/src/index.ts | 1 + .../json-field-type-polyfill-for-sqlite.ts | 4 +- packages/types/src/next-fields.ts | 92 +- packages/types/src/utils.ts | 2 +- packages/utils/CHANGELOG.md | 7 + packages/utils/package.json | 6 +- prisma-utils/.gitignore | 1 + prisma-utils/README.md | 5 + prisma-utils/package.json | 17 + prisma-utils/src/index.ts | 313 ++++ tests/admin-ui-tests/CHANGELOG.md | 9 + tests/admin-ui-tests/package.json | 10 +- tests/api-tests/CHANGELOG.md | 13 + tests/api-tests/access-control/authed.test.ts | 16 +- .../mutations-field-static.test.ts | 14 +- .../mutations-list-declarative.test.ts | 18 +- .../mutations-list-static.test.ts | 21 +- .../access-control/not-authed.test.ts | 18 +- tests/api-tests/access-control/utils.ts | 8 +- tests/api-tests/auth-header.test.ts | 5 +- .../extend-graphql-schema.test.ts | 12 +- tests/api-tests/fields/filter.test.ts | 602 ++++--- tests/api-tests/fields/types/Virtual.test.ts | 8 +- tests/api-tests/fields/types/document.test.ts | 4 +- tests/api-tests/fields/unique.test.ts | 4 + tests/api-tests/hooks/hook-errors.test.ts | 895 ++++++---- tests/api-tests/hooks/list-hooks.test.ts | 73 +- tests/api-tests/id-field.test.ts | 2 +- tests/api-tests/package.json | 10 +- tests/api-tests/queries/cache-hints.test.ts | 4 +- tests/api-tests/queries/filters.test.ts | 14 +- tests/api-tests/queries/limits.test.ts | 24 +- tests/api-tests/queries/relationships.test.ts | 40 +- .../many-to-many-one-sided.test.ts | 12 +- .../crud-self-ref/many-to-many.test.ts | 12 +- .../one-to-many-one-sided.test.ts | 10 +- .../crud-self-ref/one-to-many.test.ts | 22 +- .../crud-self-ref/one-to-one.test.ts | 28 +- .../crud/many-to-many-one-sided.test.ts | 24 +- .../relationships/crud/many-to-many.test.ts | 24 +- .../crud/one-to-many-one-sided.test.ts | 10 +- .../relationships/crud/one-to-many.test.ts | 22 +- .../relationships/crud/one-to-one.test.ts | 48 +- .../filtering/access-control.test.ts | 4 +- .../relationships/filtering/filtering.test.ts | 33 +- .../relationships/filtering/nested.test.ts | 16 +- .../relationships/many-to-one-to-one.test.ts | 38 +- .../create-and-connect-many.test.ts | 4 +- .../nested-mutations/create-many.test.ts | 14 +- .../nested-mutations/create-singular.test.ts | 6 +- .../relationships/shared-names.test.ts | 2 +- tests/api-tests/utils.ts | 82 +- tests/benchmarks/CHANGELOG.md | 9 + tests/benchmarks/package.json | 8 +- .../custom-admin-ui-pages.test.ts | 3 +- tests/examples-smoke-tests/package.json | 2 +- tests/test-projects/basic/CHANGELOG.md | 8 + tests/test-projects/basic/package.json | 6 +- tests/test-projects/basic/schema.graphql | 130 +- .../crud-notifications/CHANGELOG.md | 8 + .../crud-notifications/README.md | 4 + .../crud-notifications/keystone.ts | 23 + .../crud-notifications/package.json | 22 + .../crud-notifications/schema.graphql | 329 ++++ .../crud-notifications/schema.prisma | 27 + .../crud-notifications/schema.ts | 38 + yarn.lock | 1572 +++++++++-------- 297 files changed, 9663 insertions(+), 5030 deletions(-) delete mode 100644 .changeset/brown-glasses-complain.md delete mode 100644 .changeset/chilled-grapes-cry.md delete mode 100644 .changeset/cold-cycles-cry.md delete mode 100644 .changeset/dull-humans-yell.md delete mode 100644 .changeset/early-experts-allow.md delete mode 100644 .changeset/eleven-mayflies-kneel.md delete mode 100644 .changeset/empty-baboons-unite.md delete mode 100644 .changeset/fast-guests-tickle.md delete mode 100644 .changeset/fluffy-coins-argue.md delete mode 100644 .changeset/good-cycles-ring.md delete mode 100644 .changeset/happy-seals-cheat.md delete mode 100644 .changeset/khaki-ducks-poke.md delete mode 100644 .changeset/lovely-pears-sort.md delete mode 100644 .changeset/nasty-windows-study.md delete mode 100644 .changeset/olive-maps-serve.md delete mode 100644 .changeset/olive-poems-explode.md delete mode 100644 .changeset/proud-impalas-flash.md delete mode 100644 .changeset/rich-tomatoes-own.md delete mode 100644 .changeset/silly-impalas-type.md delete mode 100644 .changeset/smooth-moose-eat.md delete mode 100644 .changeset/strange-crabs-glow.md delete mode 100644 .changeset/tidy-suits-refuse.md delete mode 100644 .changeset/tough-geese-trade.md delete mode 100644 .changeset/wet-frogs-share.md delete mode 100644 .changeset/wise-pianos-flash.md create mode 100644 docs/babel.config.js create mode 100644 docs/pages/updates/new-graphql-api.mdx create mode 100644 docs/public/assets/guides/custom-admin-ui-pages/custom-page-completed.png create mode 100644 docs/public/assets/guides/custom-admin-ui-pages/custom-page-w-page-container.png create mode 100644 docs/public/assets/guides/custom-admin-ui-pages/custom-page-with-styled-header.png create mode 100644 docs/public/assets/guides/custom-admin-ui-pages/header-prop.png create mode 100644 docs/public/assets/guides/custom-admin-ui-pages/simple-custom-page.png create mode 100644 examples/custom-admin-ui-pages/admin/components/CustomNavigation.tsx create mode 100644 examples/custom-admin-ui-pages/admin/config.ts create mode 100644 packages/types/src/filters/enum-filter.ts create mode 100644 packages/types/src/filters/index.ts create mode 100644 packages/types/src/filters/providers/postgresql.ts create mode 100644 packages/types/src/filters/providers/sqlite.ts create mode 100644 prisma-utils/.gitignore create mode 100644 prisma-utils/README.md create mode 100644 prisma-utils/package.json create mode 100644 prisma-utils/src/index.ts create mode 100644 tests/test-projects/crud-notifications/CHANGELOG.md create mode 100644 tests/test-projects/crud-notifications/README.md create mode 100644 tests/test-projects/crud-notifications/keystone.ts create mode 100644 tests/test-projects/crud-notifications/package.json create mode 100644 tests/test-projects/crud-notifications/schema.graphql create mode 100644 tests/test-projects/crud-notifications/schema.prisma create mode 100644 tests/test-projects/crud-notifications/schema.ts diff --git a/.changeset/brown-glasses-complain.md b/.changeset/brown-glasses-complain.md deleted file mode 100644 index 1dd24fb1cbd..00000000000 --- a/.changeset/brown-glasses-complain.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@keystone-next/fields': major -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -Removed `_ListKeyMeta` and `_toManyRelationshipFieldMeta` fields. You should use `listKeyCount` and `toManyRelationshipFieldCount` instead diff --git a/.changeset/chilled-grapes-cry.md b/.changeset/chilled-grapes-cry.md deleted file mode 100644 index 8900a01a4fe..00000000000 --- a/.changeset/chilled-grapes-cry.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@keystone-next/example-ecommerce': patch -'@keystone-next/fields-document': patch -'@keystone-next/keystone': patch ---- - -Updated internal type definitions. diff --git a/.changeset/cold-cycles-cry.md b/.changeset/cold-cycles-cry.md deleted file mode 100644 index 01d444759a0..00000000000 --- a/.changeset/cold-cycles-cry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -Removed all arguments from `context.lists.List.count` and `context.db.lists.List.count` except for `where`. diff --git a/.changeset/dull-humans-yell.md b/.changeset/dull-humans-yell.md deleted file mode 100644 index 2c54e688c64..00000000000 --- a/.changeset/dull-humans-yell.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -The create one mutation now requires a non-null `data` argument and the create many mutation accepts a list of `ItemCreateInput` directly instead of being nested inside of an object with the `ItemCreateInput` in a `data` field. - -If you have a list called `Item`, `createItem` now looks like `createItem(data: ItemCreateInput!): Item` and `createItems` now looks like `createItems(data: [ItemCreateInput!]!): [Item]`. diff --git a/.changeset/early-experts-allow.md b/.changeset/early-experts-allow.md deleted file mode 100644 index 0ba0c99a6e4..00000000000 --- a/.changeset/early-experts-allow.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@keystone-next/fields': major -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -Removed `search` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `contains` filters instead. diff --git a/.changeset/eleven-mayflies-kneel.md b/.changeset/eleven-mayflies-kneel.md deleted file mode 100644 index 1dbd83a8621..00000000000 --- a/.changeset/eleven-mayflies-kneel.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@keystone-ui/notice': patch -'@keystone-ui/toast': patch ---- - -Updated css to preserve whitespace formatting of error messages. diff --git a/.changeset/empty-baboons-unite.md b/.changeset/empty-baboons-unite.md deleted file mode 100644 index 0e612be3d43..00000000000 --- a/.changeset/empty-baboons-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Removed unused code path in Admin UI error display. diff --git a/.changeset/fast-guests-tickle.md b/.changeset/fast-guests-tickle.md deleted file mode 100644 index 6fcc1576912..00000000000 --- a/.changeset/fast-guests-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/fields': patch ---- - -Updated timestamp field to default time to 00:00 when no time is selected. diff --git a/.changeset/fluffy-coins-argue.md b/.changeset/fluffy-coins-argue.md deleted file mode 100644 index 214507238cc..00000000000 --- a/.changeset/fluffy-coins-argue.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@keystone-next/example-testing': patch -'@keystone-next/keystone': patch ---- - -Added more details to validation failure error messages. diff --git a/.changeset/good-cycles-ring.md b/.changeset/good-cycles-ring.md deleted file mode 100644 index 9aefdfff97e..00000000000 --- a/.changeset/good-cycles-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/example-custom-admin-ui-pages': major ---- - -Initial version of the custom-admin-ui-pages example. diff --git a/.changeset/happy-seals-cheat.md b/.changeset/happy-seals-cheat.md deleted file mode 100644 index 3251f247d82..00000000000 --- a/.changeset/happy-seals-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': major ---- - -Removed the `uid` and `name` properties from the errors returned by the GraphQL API. diff --git a/.changeset/khaki-ducks-poke.md b/.changeset/khaki-ducks-poke.md deleted file mode 100644 index 4f3a5c1675a..00000000000 --- a/.changeset/khaki-ducks-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/fields-document': patch ---- - -Suppressed error logging during tests. diff --git a/.changeset/lovely-pears-sort.md b/.changeset/lovely-pears-sort.md deleted file mode 100644 index 4522dc1b66e..00000000000 --- a/.changeset/lovely-pears-sort.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@keystone-next/fields': major -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -Removed `sortBy` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `orderBy` instead. diff --git a/.changeset/nasty-windows-study.md b/.changeset/nasty-windows-study.md deleted file mode 100644 index ddfd1ef4d16..00000000000 --- a/.changeset/nasty-windows-study.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@keystone-next/fields': major -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -`disconnectAll` has been renamed to `disconnect` in to-one relationship inputs and the old `disconnect` field has been removed. There are also seperate input types for create and update where the input for create doesn't have `disconnect`. It's also now required that if you provide a to-one relationship input, you must provide exactly one field to the input. - -If you have a list called `Item`, the to-one relationship inputs now look like this: - -```graphql -input ItemRelateToOneForCreateInput { - create: ItemCreateInput - connect: ItemWhereUniqueInput -} -input ItemRelateToOneForUpdateInput { - create: ItemCreateInput - connect: ItemWhereUniqueInput - disconnect: Boolean -} -``` diff --git a/.changeset/olive-maps-serve.md b/.changeset/olive-maps-serve.md deleted file mode 100644 index ac2ca1c4f58..00000000000 --- a/.changeset/olive-maps-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Added more details to before/after change/delete hook error messages. diff --git a/.changeset/olive-poems-explode.md b/.changeset/olive-poems-explode.md deleted file mode 100644 index 05499df63c9..00000000000 --- a/.changeset/olive-poems-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Removed unused dependency `@graphql-tools/schema`. diff --git a/.changeset/proud-impalas-flash.md b/.changeset/proud-impalas-flash.md deleted file mode 100644 index c190c8b8943..00000000000 --- a/.changeset/proud-impalas-flash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-ui/segmented-control': patch ---- - -Fixed segmented-control focus style. diff --git a/.changeset/rich-tomatoes-own.md b/.changeset/rich-tomatoes-own.md deleted file mode 100644 index 03f9139408a..00000000000 --- a/.changeset/rich-tomatoes-own.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@keystone-next/fields': major -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -`disconnectAll` has been replaced by `set` in to-many relationship inputs, the equivalent to `disconnectAll: true` is now `set: []`. There are also seperate input types for create and update where the input for create doesn't have `disconnect` or `set`. The inputs in the lists in the input field are now also non-null. - -If you have a list called `Item`, the to-many relationship inputs now look like this: - -```graphql -input ItemRelateToManyForCreateInput { - create: [ItemCreateInput!] - connect: [ItemWhereUniqueInput!] -} -input ItemRelateToManyForUpdateInput { - disconnect: [ItemWhereUniqueInput!] - set: [ItemWhereUniqueInput!] - create: [ItemCreateInput!] - connect: [ItemWhereUniqueInput!] -} -``` diff --git a/.changeset/silly-impalas-type.md b/.changeset/silly-impalas-type.md deleted file mode 100644 index e58a4065155..00000000000 --- a/.changeset/silly-impalas-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/example-custom-admin-ui-navigation': major ---- - -Initial version of the custom-admin-ui-navigation example. diff --git a/.changeset/smooth-moose-eat.md b/.changeset/smooth-moose-eat.md deleted file mode 100644 index 63c01fa8093..00000000000 --- a/.changeset/smooth-moose-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@keystone-next/keystone": patch ---- - -Updated Prisma dependencies to `2.28.0`. diff --git a/.changeset/strange-crabs-glow.md b/.changeset/strange-crabs-glow.md deleted file mode 100644 index ada423ec843..00000000000 --- a/.changeset/strange-crabs-glow.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@keystone-next/keystone': major -'@keystone-next/types': major -'@keystone-next/fields-document': patch -'@keystone-next/fields': patch ---- - -The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. - -If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. - -Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. diff --git a/.changeset/tidy-suits-refuse.md b/.changeset/tidy-suits-refuse.md deleted file mode 100644 index 88067ac37d5..00000000000 --- a/.changeset/tidy-suits-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Updated internal error handling to use the `apollo-server-errors` package instead of `apollo-errors`. \ No newline at end of file diff --git a/.changeset/tough-geese-trade.md b/.changeset/tough-geese-trade.md deleted file mode 100644 index 02343afcfbd..00000000000 --- a/.changeset/tough-geese-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/types': patch ---- - -Updated types to allow the `'id'` field in `ui.labelField`, `ui.listView.initialColumns`, and `ui.listView.initialSort`. diff --git a/.changeset/wet-frogs-share.md b/.changeset/wet-frogs-share.md deleted file mode 100644 index e939b428e24..00000000000 --- a/.changeset/wet-frogs-share.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@keystone-next/auth': major -'@keystone-next/fields': major -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. - -If you have a list called `Item`, the update mutations now look like this: - -```graphql -type Mutation { - updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item - updateItems(data: [ItemUpdateArgs!]!): [Item] -} - -input ItemUpdateArgs { - where: ItemWhereUniqueInput! - data: ItemUpdateInput! -} -``` diff --git a/.changeset/wise-pianos-flash.md b/.changeset/wise-pianos-flash.md deleted file mode 100644 index 9a6d732caf1..00000000000 --- a/.changeset/wise-pianos-flash.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@keystone-next/keystone': major -'@keystone-next/types': major ---- - -The delete mutations now accept `where` unique inputs instead of only an `id`. - -If you have a list called `Item`, `deleteItem` now looks like `deleteItem(where: ItemWhereUniqueInput!): Item` and `deleteItems` now looks like `deleteItems(where: [ItemWhereUniqueInput!]!): [Item]` diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0e1e0d9cf98..fb9ea6031fd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -298,10 +298,10 @@ jobs: run: yarn - name: Install Dependencies of Browsers if: needs.should_run_tests.outputs.shouldRunTests == 'true' - uses: microsoft/playwright-github-action@v1 - - name: Install Browsers for Playwright + run: npx playwright install-deps + - name: Install Browsers if: needs.should_run_tests.outputs.shouldRunTests == 'true' - run: node ./node_modules/playwright/install.js + run: npx playwright install - name: Unit tests if: needs.should_run_tests.outputs.shouldRunTests == 'true' run: yarn jest --ci --runInBand tests/examples-smoke-tests/${{ matrix.test }} @@ -396,3 +396,5 @@ jobs: run: yarn lint:markdown - name: Example schemas run: yarn lint:examples + - name: Prisma Filters + run: yarn lint:filters diff --git a/.prettierignore b/.prettierignore index dd5329b7230..023ecfd4978 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,3 +8,4 @@ coverage **/.keystone docs/public/assets/ .keystone/tests +prisma-utils/src/generated diff --git a/design-system/packages/button/package.json b/design-system/packages/button/package.json index fa23ea95133..5f81ce360d2 100644 --- a/design-system/packages/button/package.json +++ b/design-system/packages/button/package.json @@ -5,10 +5,10 @@ "main": "dist/button.cjs.js", "module": "dist/button.esm.js", "devDependencies": { - "@types/react": "^17.0.15" + "@types/react": "^17.0.18" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", "@keystone-ui/icons": "^4.0.0", "@keystone-ui/loading": "^4.0.0", diff --git a/design-system/packages/core/package.json b/design-system/packages/core/package.json index ed7cad3272a..672d1c3ff4d 100644 --- a/design-system/packages/core/package.json +++ b/design-system/packages/core/package.json @@ -5,7 +5,7 @@ "main": "dist/core.cjs.js", "module": "dist/core.esm.js", "devDependencies": { - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "react": "^17.0.2", "react-dom": "^17.0.2" }, @@ -14,8 +14,8 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", - "@emotion/react": "^11.4.0", + "@babel/runtime": "^7.15.3", + "@emotion/react": "^11.4.1", "@types/facepaint": "^1.2.2", "facepaint": "^1.2.1" }, diff --git a/design-system/packages/fields/package.json b/design-system/packages/fields/package.json index 8813ee40496..a82ec123dc0 100644 --- a/design-system/packages/fields/package.json +++ b/design-system/packages/fields/package.json @@ -5,10 +5,10 @@ "main": "dist/fields.cjs.js", "module": "dist/fields.esm.js", "devDependencies": { - "@types/react": "^17.0.15" + "@types/react": "^17.0.18" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.1.0", "@keystone-ui/icons": "^4.0.0", "@keystone-ui/popover": "^4.0.2", diff --git a/design-system/packages/icons/package.json b/design-system/packages/icons/package.json index 3938ba866a9..7a3c11a6eb2 100644 --- a/design-system/packages/icons/package.json +++ b/design-system/packages/icons/package.json @@ -12,7 +12,7 @@ "@svgr/plugin-jsx": "^5.5.0", "@svgr/plugin-prettier": "^5.5.0", "@svgr/plugin-svgo": "^5.5.0", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "chalk": "^4.1.2", "feather-icons": "^4.28.0", "fs-extra": "^10.0.0", @@ -21,7 +21,7 @@ "to-pascal-case": "^1.0.0" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0" }, "peerDependencies": { diff --git a/design-system/packages/loading/package.json b/design-system/packages/loading/package.json index b037e822fec..98a7c74bebc 100644 --- a/design-system/packages/loading/package.json +++ b/design-system/packages/loading/package.json @@ -5,10 +5,10 @@ "main": "dist/loading.cjs.js", "module": "dist/loading.esm.js", "devDependencies": { - "@types/react": "^17.0.15" + "@types/react": "^17.0.18" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", "react": "^17.0.2" }, diff --git a/design-system/packages/modals/package.json b/design-system/packages/modals/package.json index b71ad2e6deb..43f4ad1d17c 100644 --- a/design-system/packages/modals/package.json +++ b/design-system/packages/modals/package.json @@ -5,10 +5,10 @@ "main": "dist/modals.cjs.js", "module": "dist/modals.esm.js", "devDependencies": { - "@types/react": "^17.0.15" + "@types/react": "^17.0.18" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.0.0", "react": "^17.0.2", diff --git a/design-system/packages/notice/CHANGELOG.md b/design-system/packages/notice/CHANGELOG.md index 54449b00a52..9f450557c56 100644 --- a/design-system/packages/notice/CHANGELOG.md +++ b/design-system/packages/notice/CHANGELOG.md @@ -1,5 +1,11 @@ # @keystone-ui/notice +## 4.0.1 + +### Patch Changes + +- [#6220](https://github.com/keystonejs/keystone/pull/6220) [`c2bb6a9a5`](https://github.com/keystonejs/keystone/commit/c2bb6a9a596fc52a3c61ec5d91c79758e417e61d) Thanks [@timleslie](https://github.com/timleslie)! - Updated css to preserve whitespace formatting of error messages. + ## 4.0.0 ### Major Changes diff --git a/design-system/packages/notice/package.json b/design-system/packages/notice/package.json index e3a225031c7..77428a5a921 100644 --- a/design-system/packages/notice/package.json +++ b/design-system/packages/notice/package.json @@ -1,14 +1,14 @@ { "name": "@keystone-ui/notice", - "version": "4.0.0", + "version": "4.0.1", "license": "MIT", "main": "dist/notice.cjs.js", "module": "dist/notice.esm.js", "devDependencies": { - "@types/react": "^17.0.15" + "@types/react": "^17.0.18" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.0.0", "@keystone-ui/icons": "^4.0.0", diff --git a/design-system/packages/options/package.json b/design-system/packages/options/package.json index 71e80dde29d..2a16ea71b94 100644 --- a/design-system/packages/options/package.json +++ b/design-system/packages/options/package.json @@ -11,7 +11,7 @@ "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", "@keystone-ui/fields": "^4.1.2", "@keystone-ui/icons": "^4.0.0", diff --git a/design-system/packages/pill/package.json b/design-system/packages/pill/package.json index 53ee6464e98..7687bdb2767 100644 --- a/design-system/packages/pill/package.json +++ b/design-system/packages/pill/package.json @@ -11,7 +11,7 @@ "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", "@keystone-ui/icons": "^4.0.0" }, diff --git a/design-system/packages/popover/package.json b/design-system/packages/popover/package.json index b1b4acb6245..52762002475 100644 --- a/design-system/packages/popover/package.json +++ b/design-system/packages/popover/package.json @@ -13,10 +13,10 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", - "@popperjs/core": "^2.9.2", - "focus-trap": "^6.6.0", + "@popperjs/core": "^2.9.3", + "focus-trap": "^6.6.1", "react-popper": "^2.2.5" }, "engines": { diff --git a/design-system/packages/segmented-control/CHANGELOG.md b/design-system/packages/segmented-control/CHANGELOG.md index 339613f37d8..537191bf60f 100644 --- a/design-system/packages/segmented-control/CHANGELOG.md +++ b/design-system/packages/segmented-control/CHANGELOG.md @@ -1,5 +1,11 @@ # @keystone-ui/segmented-control +## 4.0.2 + +### Patch Changes + +- [#6235](https://github.com/keystonejs/keystone/pull/6235) [`6cd7ab78e`](https://github.com/keystonejs/keystone/commit/6cd7ab78e018fa0ffaddc1258426d23da19cd854) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed segmented-control focus style. + ## 4.0.1 ### Patch Changes diff --git a/design-system/packages/segmented-control/package.json b/design-system/packages/segmented-control/package.json index dc1d54f67d7..51d0acd8fdd 100644 --- a/design-system/packages/segmented-control/package.json +++ b/design-system/packages/segmented-control/package.json @@ -1,15 +1,15 @@ { "name": "@keystone-ui/segmented-control", - "version": "4.0.1", + "version": "4.0.2", "license": "MIT", "main": "dist/segmented-control.cjs.js", "module": "dist/segmented-control.esm.js", "devDependencies": { - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.1.0" }, "peerDependencies": { diff --git a/design-system/packages/toast/CHANGELOG.md b/design-system/packages/toast/CHANGELOG.md index 24cfbd25711..ae0d11b3ad0 100644 --- a/design-system/packages/toast/CHANGELOG.md +++ b/design-system/packages/toast/CHANGELOG.md @@ -1,5 +1,11 @@ # @keystone-ui/toast +## 4.0.2 + +### Patch Changes + +- [#6220](https://github.com/keystonejs/keystone/pull/6220) [`c2bb6a9a5`](https://github.com/keystonejs/keystone/commit/c2bb6a9a596fc52a3c61ec5d91c79758e417e61d) Thanks [@timleslie](https://github.com/timleslie)! - Updated css to preserve whitespace formatting of error messages. + ## 4.0.1 ### Patch Changes diff --git a/design-system/packages/toast/package.json b/design-system/packages/toast/package.json index 13eebb8f486..3c1ebc4c2df 100644 --- a/design-system/packages/toast/package.json +++ b/design-system/packages/toast/package.json @@ -1,15 +1,15 @@ { "name": "@keystone-ui/toast", - "version": "4.0.1", + "version": "4.0.2", "license": "MIT", "main": "dist/toast.cjs.js", "module": "dist/toast.esm.js", "devDependencies": { - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", "@keystone-ui/icons": "^4.0.0" }, diff --git a/design-system/packages/tooltip/package.json b/design-system/packages/tooltip/package.json index 8d1769949e8..57cefc86d4d 100644 --- a/design-system/packages/tooltip/package.json +++ b/design-system/packages/tooltip/package.json @@ -13,7 +13,7 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/core": "^3.0.0", "@keystone-ui/popover": "^4.0.0", "apply-ref": "^1.0.0" diff --git a/design-system/website/package.json b/design-system/website/package.json index 80c912e0e83..f5816f89485 100644 --- a/design-system/website/package.json +++ b/design-system/website/package.json @@ -7,7 +7,7 @@ "dev": "next -p 8080" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.0.0", "@keystone-ui/fields": "^4.1.2", @@ -21,7 +21,7 @@ "@keystone-ui/toast": "^4.0.1", "@keystone-ui/tooltip": "^4.0.0", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "@types/react-dom": "^17.0.9", "@types/tinycolor2": "^1.4.3", "@types/webpack": "^4.41.30", diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 201702ee365..a1174b7a435 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,12 @@ # @keystone-next/website +## 3.1.4 + +### Patch Changes + +- Updated dependencies [[`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`e985aa010`](https://github.com/keystonejs/keystone/commit/e985aa0104d30a779f21ec05d80e6b98ece87dfb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`69f47bfed`](https://github.com/keystonejs/keystone/commit/69f47bfed1eaa1269cfdc42071268a914bd4aa17), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda)]: + - @keystone-next/fields-document@8.0.0 + ## 3.1.3 ### Patch Changes diff --git a/docs/babel.config.js b/docs/babel.config.js new file mode 100644 index 00000000000..8808c5f11d7 --- /dev/null +++ b/docs/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../babel.config'); diff --git a/docs/components/docs/Navigation.tsx b/docs/components/docs/Navigation.tsx index e4e4f641ca5..f854aea01c7 100644 --- a/docs/components/docs/Navigation.tsx +++ b/docs/components/docs/Navigation.tsx @@ -136,28 +136,22 @@ export function DocsNavigation() { Keystone 5 vs 6 Command Line Relationships - Query Filters + + Query Filters Updated + Hooks Document Fields Document Field Demo - - Virtual Fields New - - - Testing New - + Virtual Fields + Testing - Custom Fields New - - - Custom Admin UI Logo New + Custom Fields Updated + Custom Admin UI Logo - Custom Admin UI Pages New - - - Custom Admin UI Navigation New + Custom Admin UI Pages Updated + Custom Admin UI Navigation Access Control @@ -190,8 +184,12 @@ export function DocsNavigation() { DB Item API GraphQL - GraphQL API - Query Filter API + + GraphQL API Updated + + + Query Filter API Updated + ); diff --git a/docs/next-env.d.ts b/docs/next-env.d.ts index 7b7aa2c7727..f87ea7fa66a 100644 --- a/docs/next-env.d.ts +++ b/docs/next-env.d.ts @@ -1,2 +1,4 @@ +// @ts-ignore /// /// +/// diff --git a/docs/next.config.js b/docs/next.config.js index e3c02223414..cd2df154aed 100644 --- a/docs/next.config.js +++ b/docs/next.config.js @@ -1,6 +1,5 @@ const withPreconstruct = require('@preconstruct/next'); const withPlugins = require('next-compose-plugins'); -const withImages = require('next-images'); const mdxHints = require('remark-hint'); const gfm = require('remark-gfm'); @@ -20,7 +19,6 @@ const redirects = { module.exports = withPlugins([ withPreconstruct, - withImages, [ withMDX, { @@ -31,9 +29,7 @@ module.exports = withPlugins([ nextConfig.env = { siteUrl: 'https://keystonejs.com', }; - nextConfig.future = { - webpack5: true, - }; + nextConfig.eslint = { ignoreDuringBuilds: true }; nextConfig.typescript = { ...nextConfig.typescript, // we run TS elsewhere, Next runs against a different TS config which it insists on existing diff --git a/docs/package.json b/docs/package.json index 7e15ef884bb..4020fe7a8a1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/website", - "version": "3.1.3", + "version": "3.1.4", "private": true, "license": "MIT", "scripts": { @@ -13,20 +13,20 @@ "cypress:run:ci": "yarn build && start-server-and-test start http://localhost:8000 cy:run" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@emotion/cache": "11.4.0", - "@emotion/react": "^11.4.0", + "@emotion/react": "^11.4.1", "@emotion/server": "11.4.0", "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/fields-document": "^7.0.2", + "@keystone-next/fields-document": "^8.0.0", "@mdx-js/loader": "next", "@mdx-js/react": "^1.6.22", - "@next/mdx": "^10.2.3", + "@next/mdx": "^11.1.0", "@preconstruct/next": "^3.0.0", "@sindresorhus/slugify": "^1.1.2", "@types/gtag.js": "^0.0.7", "@types/mdx-js__react": "^1.5.4", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "@types/react-dom": "^17.0.9", "@types/webpack": "^4.41.30", "classnames": "^2.3.1", @@ -34,9 +34,8 @@ "cypress": "^5.6.0", "date-fns": "^2.23.0", "facepaint": "^1.2.1", - "next": "^10.2.3", + "next": "npm:next@^11.1.0", "next-compose-plugins": "^2.2.1", - "next-images": "^1.8.1", "prism-react-renderer": "^1.2.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -46,7 +45,7 @@ "remark-hint": "^1.0.10" }, "devDependencies": { - "next-sitemap": "^1.6.140", + "next-sitemap": "^1.6.157", "start-server-and-test": "^1.13.1", "typescript": "^4.3.5" }, diff --git a/docs/pages/docs/apis/access-control.mdx b/docs/pages/docs/apis/access-control.mdx index b44076c2b11..d408568a48d 100644 --- a/docs/pages/docs/apis/access-control.mdx +++ b/docs/pages/docs/apis/access-control.mdx @@ -105,7 +105,7 @@ export default config({ ListKey: list({ fields: { isLocked: checkbox() }, // Declarative access control definition - access: { isLocked: false }, + access: { isLocked: { equals: false } }, }), }), }); diff --git a/docs/pages/docs/apis/auth.mdx b/docs/pages/docs/apis/auth.mdx index 2026ab6e974..bca3897dbd6 100644 --- a/docs/pages/docs/apis/auth.mdx +++ b/docs/pages/docs/apis/auth.mdx @@ -78,11 +78,11 @@ const { withAuth } = createAuth({ The following elements will be added to the GraphQL API. ```graphql -Mutation { +type Mutation { authenticateUserWithPassword(email: String!, password: String!): UserAuthenticationWithPasswordResult! } -Query { +type Query { authenticatedItem: AuthenticatedItem } @@ -188,7 +188,7 @@ const { withAuth } = createAuth({ Enabling `initFirstItem` will add the following elements to the GraphQL API. ```graphql -Mutation { +type Mutation { createInitialUser(data: CreateInitialUserInput!): UserAuthenticationWithPasswordSuccess! } @@ -274,12 +274,12 @@ const fields = { Enabling `passwordResetLink` will add the following elements to the GraphQL API. ```graphql -Mutation { +type Mutation { sendUserPasswordResetLink(email: String!): SendUserPasswordResetLinkResult redeemUserPasswordResetToken(email: String!, token: String!, password: String!): RedeemUserPasswordResetTokenResult } -Query { +type Query { validateUserPasswordResetToken(email: String!, token: String!): ValidateUserPasswordResetTokenResult } @@ -413,7 +413,7 @@ const fields = { Enabling `magicAuthLink` will add the following elements to the GraphQL API. ```graphql -Mutation { +type Mutation { sendUserMagicAuthLink(email: String!): SendUserMagicAuthLinkResult redeemUserMagicAuthToken(email: String!, token: String!): RedeemUserMagicAuthTokenResult! } diff --git a/docs/pages/docs/apis/config.mdx b/docs/pages/docs/apis/config.mdx index aa881ffab0e..3b6e7618400 100644 --- a/docs/pages/docs/apis/config.mdx +++ b/docs/pages/docs/apis/config.mdx @@ -119,13 +119,15 @@ The `sqlite` provider is not intended to be used in production systems, and has - `decimal`: The `decimal` field type is not supported. - `timestamp`: The `timestamp` field type only supports times within the range `1970 - 2038`. -- `text`: The `text` field type does not support the advanced filtering operations `contains`, `starts_with`, `ends_with`, or case insensitive filtering. -- `autoIncrement`: The `autoIncrement` field type can only be used as an `id` field. +- `text`: The `text` field type does not support setting a filter as case sensitive or insensitive. + Assuming default collation, all the filters except `contains`, `startsWith` and `endsWith` will be case sensitive + and `contains`, `startsWith` and `endsWith` will be case insensitive but only for ASCII characters. +- `autoIncrement`: The `autoIncrement` field type is not supported. - `select`: Using the `dataType: 'enum'` will use a GraphQL `String` type, rather than an `Enum` type. ## ui -``` +```ts import type { AdminUIConfig } from '@keystone-next/types'; ``` @@ -277,6 +279,8 @@ It has a TypeScript type of `GraphQLConfig`. Options: +- `debug` (default: `process.env.NODE_ENV !== 'production'`): If `true`, stacktraces from both Apollo errors and Keystone errors will be included in the errors returned from the GraphQL API. + These can be filtered out with `apolloConfig.formatError` if you need to process them, but do not want them returned over the GraphQL API. - `queryLimits` (default: `undefined`): Allows you to limit the total number of results returned from a query to your GraphQL API. See also the per-list `graphql.queryLimits` option in the [Schema API](./schema). - `apolloConfig` (default: `undefined`): Allows you to pass extra options into the `ApolloServer` constructor. @@ -287,6 +291,7 @@ Options: ```typescript export default config({ graphql: { + debug: process.env.NODE_ENV !== 'production', queryLimits: { maxTotalResults: 100 }, apolloConfig: { playground: process.env.NODE_ENV !== 'production', diff --git a/docs/pages/docs/apis/db-items.mdx b/docs/pages/docs/apis/db-items.mdx index 80544c7d345..e857f995535 100644 --- a/docs/pages/docs/apis/db-items.mdx +++ b/docs/pages/docs/apis/db-items.mdx @@ -16,14 +16,14 @@ For each list in your system the following API is available at `context.db.lists ``` { findOne({ where: { id } }), - findMany({ where, first, skip, sortBy }), - count({ where, first, skip }), + findMany({ where, take, skip, orderBy }), + count({ where }), createOne({ data }), createMany({ data }), - updateOne({ id, data }), + updateOne({ where, data }), updateMany({ data }), - deleteOne({ id }), - deleteMany({ ids }), + deleteOne({ where }), + deleteMany({ where }), } ``` @@ -44,10 +44,10 @@ All arguments are optional. ```typescript const users = await context.db.lists.User.findMany({ - where: { name_starts_with: 'A' }, - first: 10, + where: { name: { startsWith: 'A' } }, + take: 10, skip: 20, - sortBy: ['name_ASC'], + orderBy: [{ name: 'asc' }], }); ``` @@ -57,9 +57,7 @@ All arguments are optional. ```typescript const count = await context.db.lists.User.count({ - where: { name_starts_with: 'A' }, - first: 10, - skip: 20, + where: { name: { startsWith: 'A' } }, }); ``` @@ -80,16 +78,12 @@ const user = await context.db.lists.User.createOne({ const users = await context.db.lists.User.createMany({ data: [ { - data: { - name: 'Alice', - posts: [{ create: { title: 'Alices first post' } }], - }, + name: 'Alice', + posts: [{ create: { title: 'Alices first post' } }], }, { - data: { - name: 'Bob', - posts: [{ create: { title: 'Bobs first post' } }], - }, + name: 'Bob', + posts: [{ create: { title: 'Bobs first post' } }], }, ], }); @@ -99,7 +93,7 @@ const users = await context.db.lists.User.createMany({ ```typescript const user = await context.db.lists.User.updateOne({ - id: '...', + where: { id: '...' }, data: { name: 'Alice', posts: { create: [{ title: 'My first post' }] }, @@ -113,14 +107,14 @@ const user = await context.db.lists.User.updateOne({ const users = await context.db.lists.User.updateMany({ data: [ { - id: '...', + where: { id: '...' }, data: { name: 'Alice', posts: [{ create: { title: 'Alices first post' } }], }, }, { - id: '...', + where: { id: '...' }, data: { name: 'Bob', posts: [{ create: { title: 'Bobs first post' } }], @@ -134,15 +128,15 @@ const users = await context.db.lists.User.updateMany({ ```typescript const user = await context.db.lists.User.deleteOne({ - id: '...', + where: { id: '...' }, }); ``` ### deleteMany ```typescript -const user = await context.db.lists.User.deleteMany({ - ids: ['...', '...'], +const users = await context.db.lists.User.deleteMany({ + where: [{ id: '...' }, { id: '...' }], }); ``` diff --git a/docs/pages/docs/apis/filters.mdx b/docs/pages/docs/apis/filters.mdx index 6fbee0d3c38..5e58fc12cad 100644 --- a/docs/pages/docs/apis/filters.mdx +++ b/docs/pages/docs/apis/filters.mdx @@ -6,30 +6,27 @@ Each field type provides its own set of filters which can be used with [queries] This page lists all the filters available for each field type. For more details on how to use filters in queries please consult to the [GraphQL Queries - Filters](../guides/filters) guide. -Keystone filters are typically named after the field they are filtering. For example, a `text` field called `foo` would have filters named `foo_starts_with`, `foo_contains`, etc. -In all the examples below we will use a field named `foo` as the base of the filter names. - ## Scalar types ### checkbox -| **Filter name** | **Type** | **Description** | -| --------------- | --------- | --------------- | -| `foo` | `Boolean` | Equals | -| `foo_not` | `Boolean` | Does not equal | +| **Filter name** | **Type** | **Description** | +| --------------- | ----------------------- | ------------------------------- | +| `equals` | `Boolean` | Equals | +| `not` | `BooleanNullableFilter` | Does not match the inner filter | ### integer -| **Filter name** | **Type** | **Description** | -| --------------- | -------- | --------------------- | -| `foo` | `Int` | Equals | -| `foo_not` | `Int` | Does not equal | -| `foo_lt` | `Int` | Less than | -| `foo_lte` | `Int` | Less than or equal | -| `foo_gt` | `Int` | Greater than | -| `foo_gte` | `Int` | Greater than or equal | -| `foo_in` | `[Int]` | Is in the array | -| `foo_not_in` | `[Int]` | Is not in the array | +| **Filter name** | **Type** | **Description** | +| --------------- | ------------------- | ------------------------------- | +| `equals` | `Int` | Equals | +| `lt` | `Int` | Less than | +| `lte` | `Int` | Less than or equal | +| `gt` | `Int` | Greater than | +| `gte` | `Int` | Greater than or equal | +| `in` | `[Int!]` | Is in the array | +| `notIn` | `[Int!]` | Is not in the array | +| `not` | `IntNullableFilter` | Does not match the inner filter | ### json @@ -37,67 +34,69 @@ The `json` field type does not support filters. ### float -| **Filter name** | **Type** | **Description** | -| --------------- | --------- | --------------------- | -| `foo` | `Float` | Equals | -| `foo_not` | `Float` | Does not equal | -| `foo_lt` | `Float` | Less than | -| `foo_lte` | `Float` | Less than or equal | -| `foo_gt` | `Float` | Greater than | -| `foo_gte` | `Float` | Greater than or equal | -| `foo_in` | `[Float]` | Is in the array | -| `foo_not_in` | `[Float]` | Is not in the array | +| **Filter name** | **Type** | **Description** | +| --------------- | --------------------- | ------------------------------- | +| `equals` | `Float` | Equals | +| `lt` | `Float` | Less than | +| `lte` | `Float` | Less than or equal | +| `gt` | `Float` | Greater than | +| `gte` | `Float` | Greater than or equal | +| `in` | `[Float!]` | Is in the array | +| `notIn` | `[Float!]` | Is not in the array | +| `not` | `FloatNullableFilter` | Does not match the inner filter | ### password | **Filter name** | **Type** | **Description** | | --------------- | --------- | --------------- | -| `foo_is_set` | `Boolean` | A value is set | +| `isSet` | `Boolean` | A value is set | ### select -| **Filter name** | **Type** | **Description** | -| --------------- | ---------- | ------------------- | -| `foo` | `String` | Equals | -| `foo_not` | `String` | Does not equal | -| `foo_in` | `[String]` | Is in the array | -| `foo_not_in` | `[String]` | Is not in the array | +- If the `dataType` is `string`(the default), the same filters as `text` will be available. +- If the `dataType` is `integer`, the same filters as `integer` will be available. +- If the `dataType` is `enum`, the following filters will be available: + | **Filter name** | **Type** | **Description** | + | --------------- | ---------- | ------------------- | + | `equals` | `ListKeyFieldKeyType` | Equals | + | `in` | `[ListKeyFieldKeyType!]` | Is in the array | + | `notIn` | `[ListKeyFieldKeyType!]` | Is not in the array | + | `not` | `ListKeyFieldKeyTypeNullableFilter` | Does not match the inner filter | ### text -| **Filter name** | **Type** | **Description** | ** Notes ** | -| ----------------------- | ---------- | -------------------------------------- | ----------------- | -| `foo` | `String` | Equals | -| `foo_not` | `String` | Does not equal | -| `foo_contains` | `String` | Contains | -| `foo_not_contains` | `String` | Does not contain | -| `foo_starts_with` | `String` | Starts with | `postgresql` only | -| `foo_not_starts_with` | `String` | Does not start with | `postgresql` only | -| `foo_ends_with` | `String` | Ends with | `postgresql` only | -| `foo_not_ends_with` | `String` | Does not end with | `postgresql` only | -| `foo_i` | `String` | Equals (case insensitive) | `postgresql` only | -| `foo_not_i` | `String` | Does not equal (case insensitive) | `postgresql` only | -| `foo_contains_i` | `String` | Contains (case insensitive) | `postgresql` only | -| `foo_not_contains_i` | `String` | Does not contain (case insensitive) | `postgresql` only | -| `foo_starts_with_i` | `String` | Starts with (case insensitive) | `postgresql` only | -| `foo_not_starts_with_i` | `String` | Does not start with (case insensitive) | `postgresql` only | -| `foo_ends_with_i` | `String` | Ends with (case insensitive) | `postgresql` only | -| `foo_not_ends_with_i` | `String` | Does not end with (case insensitive) | `postgresql` only | -| `foo_in` | `[String]` | Is in the array | -| `foo_not_in` | `[String]` | Is not in the array | +| **Filter name** | **Type** | **Description** | **Notes** | +| --------------- | ---------------------------------------- | ----------------------------------------------------- | --------- | +| `equals` | `String` | Equals | +| `lt` | `String` | Less than | +| `lte` | `String` | Less than or equal | +| `gt` | `String` | Greater than | +| `gte` | `String` | Greater than or equal | +| `contains` | `String` | Contains | [1] | +| `startsWith` | `String` | Starts with | [1] | +| `endsWith` | `String` | Ends with | [1] | +| `in` | `[String!]` | Is in the array | +| `notIn` | `[String!]` | Is not in the array | +| `mode` | `QueryMode` (`default` or `insensitive`) | Whether the filters should be case insensitive or not | [2] | +| `not` | `NestedStringNullableFilter` | Does not match the inner filter | + +#### Notes + +- [1] Will follow the setting of the `mode` on `postgresql` and will be case insensitive but only for ASCII characters on `sqlite` +- [2] `postgresql` only ### timestamp -| **Filter name** | **Type** | **Description** | -| --------------- | ---------- | --------------------- | -| `foo` | `String` | Equals | -| `foo_not` | `String` | Does not equal | -| `foo_lt` | `String` | Less than | -| `foo_lte` | `String` | Less than or equal | -| `foo_gt` | `String` | Greater than | -| `foo_gte` | `String` | Greater than or equal | -| `foo_in` | `[String]` | Is in the array | -| `foo_not_in` | `[String]` | Is not in the array | +| **Filter name** | **Type** | **Description** | +| --------------- | ------------------------ | ------------------------------- | +| `equals` | `String` | Equals | +| `lt` | `String` | Less than | +| `lte` | `String` | Less than or equal | +| `gt` | `String` | Greater than | +| `gte` | `String` | Greater than or equal | +| `in` | `[String!]` | Is in the array | +| `notIn` | `[String!]` | Is not in the array | +| `not` | `DateTimeNullableFilter` | Does not match the inner filter | ## Relationship type @@ -107,31 +106,30 @@ The `json` field type does not support filters. | **Filter name** | **Type** | **Description** | | --------------- | --------------- | ------------------------------------------ | -| `foos_every` | `FooWhereInput` | All related items match the nested filter | -| `foos_some` | `FooWhereInput` | Some related items match the nested filter | -| `foos_none` | `FooWhereInput` | No related items match the nested filter | +| `every` | `FooWhereInput` | All related items match the nested filter | +| `some` | `FooWhereInput` | Some related items match the nested filter | +| `none` | `FooWhereInput` | No related items match the nested filter | #### many: false | **Filter name** | **Type** | **Description** | | --------------- | --------------- | ------------------------- | | `foo` | `FooWhereInput` | Matches the nested filter | -| `foo_is_null` | `Boolean` | Is `null` | ## Index types ### autoIncrement -| **Filter name** | **Type** | **Description** | -| --------------- | -------- | --------------------- | -| `id` | `ID` | Equals | -| `id_not` | `ID` | Does not equal | -| `id_lt` | `ID` | Less than | -| `id_lte` | `ID` | Less than or equal | -| `id_gt` | `ID` | Greater than | -| `id_gte` | `ID` | Greater than or equal | -| `id_in` | `[ID]` | Is in the array | -| `id_not_in` | `[ID]` | Is not in the array | +| **Filter name** | **Type** | **Description** | +| --------------- | ------------------- | ------------------------------- | +| `equals` | `Int` | Equals | +| `lt` | `Int` | Less than | +| `lte` | `Int` | Less than or equal | +| `gt` | `Int` | Greater than | +| `gte` | `Int` | Greater than or equal | +| `in` | `[Int!]` | Is in the array | +| `notIn` | `[Int!]` | Is not in the array | +| `not` | `IntNullableFilter` | Does not match the inner filter | ## Virtual type diff --git a/docs/pages/docs/apis/graphql.mdx b/docs/pages/docs/apis/graphql.mdx index 4299ec7f2b2..37c9099195d 100644 --- a/docs/pages/docs/apis/graphql.mdx +++ b/docs/pages/docs/apis/graphql.mdx @@ -24,18 +24,14 @@ This system will generate the following GraphQL API. ```graphql type Query { - User(where: UserWhereUniqueInput!): User - allUsers(where: UserWhereInput, search: String, orderBy: [UserOrderByInput!]! = [], first: Int, skip: Int! = 0): [User] - _allUsersMeta(where: UserWhereInput, search: String, orderBy: [UserOrderByInput!]! = [], first: Int, skip: Int! = 0): _QueryMeta -} - -type Mutation { - createUser(data: UserCreateInput): User - createUsers(data: [UsersCreateInput]): [User] - updateUser(id: ID!, data: UserUpdateInput): User - updateUsers(data: [UsersUpdateInput]): [User] - deleteUser(id: ID!): User - deleteUsers(ids: [ID!]): [User] + users( + where: UserWhereInput! = {} + orderBy: [UserOrderByInput!]! = [] + take: Int + skip: Int! = 0 + ): [User!] + user(where: UserWhereUniqueInput!): User + usersCount(where: UserWhereInput! = {}): Int } type User { @@ -43,39 +39,61 @@ type User { name: String } -input UserWhereInput { - AND: [UserWhereInput!] - OR: [UserWhereInput!] +input UserWhereUniqueInput { id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_starts_with: String - name_not_starts_with: String - name_ends_with: String - name_not_ends_with: String - name_i: String - name_not_i: String - name_contains_i: String - name_not_contains_i: String - name_starts_with_i: String - name_not_starts_with_i: String - name_ends_with_i: String - name_not_ends_with_i: String - name_in: [String] - name_not_in: [String] } -input UserWhereUniqueInput { - id: ID +input UserWhereInput { + AND: [UserWhereInput!] + OR: [UserWhereInput!] + NOT: [UserWhereInput!] + id: IDFilter + name: StringNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + mode: QueryMode + not: NestedStringNullableFilter +} + +enum QueryMode { + default + insensitive +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } input UserOrderByInput { @@ -88,83 +106,116 @@ enum OrderDirection { desc } +type Mutation { + createUser(data: UserCreateInput!): User + createUsers(data: [UserCreateInput!]!): [User] + updateUser(where: UserWhereUniqueInput!, data: UserUpdateInput!): User + updateUsers(data: [UserUpdateArgs!]!): [User] + deleteUser(where: UserWhereUniqueInput!): User + deleteUsers(where: [UserWhereUniqueInput!]!): [User] +} + input UserUpdateInput { name: String } -input UsersUpdateInput { - id: ID! - data: UserUpdateInput +input UserUpdateArgs { + where: UserWhereUniqueInput! + data: UserUpdateInput! } input UserCreateInput { name: String } - -input UsersCreateInput { - data: UserCreateInput -} - -type _QueryMeta { - count: Int -} ``` ## Queries -### User +### user ```graphql type Query { - User(where: UserWhereUniqueInput!): User -} - -input UserWhereUniqueInput { - id: ID + user(where: UserWhereUniqueInput!): User } type User { id: ID! name: String } + +input UserWhereUniqueInput { + id: ID +} ``` -### allUsers +### users ```graphql type Query { - allUsers(where: UserWhereInput, search: String, orderBy: [UserOrderByInput!]! = [], first: Int, skip: Int! = 0): [User] + users( + where: UserWhereInput! = {} + orderBy: [UserOrderByInput!]! = [] + take: Int + skip: Int! = 0 + ): [User!] +} + +type User { + id: ID! + name: String } input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_starts_with: String - name_not_starts_with: String - name_ends_with: String - name_not_ends_with: String - name_i: String - name_not_i: String - name_contains_i: String - name_not_contains_i: String - name_starts_with_i: String - name_not_starts_with_i: String - name_ends_with_i: String - name_not_ends_with_i: String - name_in: [String] - name_not_in: [String] + NOT: [UserWhereInput!] + id: IDFilter + name: StringNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + mode: QueryMode + not: NestedStringNullableFilter +} + +enum QueryMode { + default + insensitive +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } input UserOrderByInput { @@ -176,63 +227,66 @@ enum OrderDirection { asc desc } - -type User { - id: ID! - name: String -} ``` ### usersCount ```graphql type Query { - usersCount(where: UserWhereInput! = {}): Int! + usersCount(where: UserWhereInput! = {}): Int } input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_starts_with: String - name_not_starts_with: String - name_ends_with: String - name_not_ends_with: String - name_i: String - name_not_i: String - name_contains_i: String - name_not_contains_i: String - name_starts_with_i: String - name_not_starts_with_i: String - name_ends_with_i: String - name_not_ends_with_i: String - name_in: [String] - name_not_in: [String] -} - -input UserOrderByInput { - id: OrderDirection - name: OrderDirection -} - -enum OrderDirection { - asc - desc -} - -type _QueryMeta { - count: Int + NOT: [UserWhereInput!] + id: IDFilter + name: StringNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + mode: QueryMode + not: NestedStringNullableFilter +} + +enum QueryMode { + default + insensitive +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } ``` @@ -242,7 +296,7 @@ type _QueryMeta { ```graphql type Mutation { - createUser(data: UserCreateInput): User + createUser(data: UserCreateInput!): User } input UserCreateInput { @@ -259,11 +313,7 @@ type User { ```graphql type Mutation { - createUsers(data: [UsersCreateInput]): [User] -} - -input UsersCreateInput { - data: UserCreateInput + createUsers(data: [UserCreateInput!]!): [User] } input UserCreateInput { @@ -280,7 +330,11 @@ type User { ```graphql type Mutation { - updateUser(id: ID!, data: UserUpdateInput): User + updateUser(where: UserWhereUniqueInput!, data: UserUpdateInput!): User +} + +input UserWhereUniqueInput { + id: ID } input UserUpdateInput { @@ -297,12 +351,16 @@ type User { ```graphql type Mutation { - updateUsers(data: [UsersUpdateInput]): [User] + updateUsers(data: [UserUpdateArgs!]!): [User] } -input UsersUpdateInput { - id: ID! - data: UserUpdateInput +input UserUpdateArgs { + where: UserWhereUniqueInput! + data: UserUpdateInput! +} + +input UserWhereUniqueInput { + id: ID } input UserUpdateInput { @@ -319,7 +377,11 @@ type User { ```graphql type Mutation { - deleteUser(id: ID!): User + deleteUser(where: UserWhereUniqueInput!): User +} + +input UserWhereUniqueInput { + id: ID } type User { @@ -332,7 +394,11 @@ type User { ```graphql type Mutation { - deleteUsers(ids: [ID!]): [User] + deleteUsers(ids: [UserWhereUniqueInput!]!): [User] +} + +input UserWhereUniqueInput { + id: ID } type User { diff --git a/docs/pages/docs/apis/list-items.mdx b/docs/pages/docs/apis/list-items.mdx index f8559c0d52a..12630497fd1 100644 --- a/docs/pages/docs/apis/list-items.mdx +++ b/docs/pages/docs/apis/list-items.mdx @@ -8,14 +8,14 @@ For each list in your system the following API is available at `context.lists. **Note:** This feature will improve over time. It has been released ahead of time to unblock developers. We are working on improving support for other styling frameworks besides Emotion and will be making it easier by exporting more Admin UI components in the near future. +In this guide we'll show you how to add custom pages to the Keystone Admin UI. +As the Admin UI is built on top of [Next.js](https://nextjs.org/docs/basic-features/pages), it exposes the same pages directory for adding custom pages. To create a custom page, ensure that the `admin/pages` directory exists in the root of your Keystone Project. Much like with Next.js, all files in this directory will be added as routes to the Admin UI. The default export of every file in this directory is expected to be a valid React Component rendered out as the contents of the route. ```tsx -// admin/pages/MyCustomPage.tsx -export default function () { +// admin/pages/custom-page.tsx +export default function CustomPage () { return ( <>

    This is a custom Admin UI Page

    -

    It can be accessed via the route '/MyCustomPage'

    +

    It can be accessed via the route /custom-page

    ) } ``` -If you have styling constraints, we recommend using the jsx export from the `@keystone-ui/core` package, as this will ensure that the version of emotion you're using conforms with the version of emotion used internally within Keystone. +x> **Not all Next.js exports are available:** Keystone **only** supports the page component as a default export in the pages directory. This means that unlike with Next, auxillary exports such as `getStaticProps` and `getServerProps` are not supported. + +With this in place, we now have a nice simple custom Admin UI page at `http://localhost:3000/custom-page`. +![example of a simple custom-page in the Admin UI](/assets/guides/custom-admin-ui-pages/simple-custom-page.png) + +## Adding Admin UI layout + +At the moment this page is pretty bare bones. We want our page to look more like an Admin UI page. +Keystone helps us do this via the `PageContainer` component exported from `@keystone-next/keystone/admin-ui/components`. + +The `PageContainer` component takes a `header` prop, which is expected to be a `ReactElement`. +This `header` prop is rendered out as the page title at the top of the page. + +```tsx +// admin/pages/custom-page.tsx +import { PageContainer } from '@keystone-next/keystone/admin-ui/components'; +export default function CustomPage () { + return ( + +

    This is a custom Admin UI Page

    +

    It can be accessed via the route /custom-page

    +
    + ) +} +``` + +With the above snippet, our custom page looks a lot more like the other pages in the Admin UI. +![example of the custom Admin UI page with the PageContainer component](/assets/guides/custom-admin-ui-pages/custom-page-w-page-container.png) + +There's still a problem though, the header doesn't look right. If we compare the header of our custom page with the header for the Dashboard, there's quite a bit of difference in the styling and font-weight. +![example of the Dashboard header element](/assets/guides/custom-admin-ui-pages/header-prop.png) + +Keystone pages leverage the `Heading` component from the `@keystone-ui/core` package to style the header, so let's use this to give our header the same styling. + +```tsx +// admin/pages/custom-page.tsx +import { PageContainer } from '@keystone-next/keystone/admin-ui/components'; +import { Heading } from '@keystone-ui/core'; + +export default function CustomPage () { + return ( + Custom Page}> +

    This is a custom Admin UI Page

    +

    It can be accessed via the route `/custom-page`

    +
    + ) +} +``` + +Much better, our custom page looks and feels like an Admin UI page now. +![custom page with correctly styled header](/assets/guides/custom-admin-ui-pages/custom-page-with-styled-header.png) + +## Custom route in Admin UI Navigation + +Yes, our custom page is looking pretty great, and much more like an Admin UI page, but it's not visible as a navigation item. +We can fix this by adding a custom Navigation component with a route pointing to our custom page. + +First add the following files to the `/admin` directory in the root of your Keystone project. + +```tsx +// admin/config.ts +import type { AdminConfig } from '@keystone-next/types'; +import { CustomNavigation } from './components/CustomNavigation'; +export const components: AdminConfig['components']= { + Navigation: CustomNavigation +}; +``` + +```tsx +// admin/components/CustomNavigation.tsx +import { NavigationContainer, ListNavItems, NavItem } from '@keystone-next/keystone/admin-ui/components'; +import type { NavigationProps } from '@keystone-next/keystone/admin-ui/components'; +export function CustomNavigation({ lists, authenticatedItem }: NavigationProps) { + return ( + + Dashboard + + + ) +} +``` + +!> You will need to restart your Keystone system after adding `admin/config.ts` for the custom Navigation component to be loaded. + +!> If you're interested in more details on creating a custom Navigation component check out the [Custom Admin UI Navigation](/docs/guides/custom-admin-ui-navigation) guide. + +Lastly we'll add our new route to the newly created `CustomNavigation` component. ```tsx -// admin/pages/MyCustomPage.tsx +// admin/components/CustomNavigation.tsx +import { NavigationContainer, ListNavItems, NavItem } from '@keystone-next/keystone/admin-ui/components'; +import type { NavigationProps } from '@keystone-next/keystone/admin-ui/components'; +export function CustomNavigation({ lists, authenticatedItem }: NavigationProps) { + return ( + + Dashboard + + Custom Page + + ) +} +``` + +!> Under the hood Keystone's Admin UI is powered by Next.js, so the route to our custom page is the filename of our custom page component. In this case it's `/custom-page`. + +With all that in place, our custom Admin UI page is now navigable from the Admin UI Navigation component, and we can access it from other pages in the Admin UI. +![completed custom Admin UI page](/assets/guides/custom-admin-ui-pages/custom-page-completed.png) + +## Styling + +There are other styling considerations when adding a custom page to the Admin UI that go beyond making it _look_ and _feel_ like an Admin UI page. +For this, we recommend using the `jsx` runtime export from the `@keystone-ui/core` package, as this will ensure that the version of [emotion](https://emotion.sh/docs/introduction) you're using conforms with the version of emotion used internally used by Keystone. + +The snippet below uses the emotion `jsx` runtime exported from `@keystone-ui/core` to help add some basic allignment and layout styling to the contents of our Admin UI custom page. + +```tsx +// admin/pages/custom-page.tsx /** @jsxRuntime classic */ /** @jsx jsx */ + import { jsx } from '@keystone-ui/core'; -export default function () { +import { PageContainer } from '@keystone-next/keystone/admin-ui/components'; +import { Heading } from '@keystone-ui/core'; + +export default function CustomPage () { return ( - <> + + Custom Page + + )}>

    This is a custom Admin UI Page

    -

    It can be accessed via the route '/MyCustomPage'

    - + width: '100%', + textAlign: 'center', + }}> + This is a custom Admin UI Page + +

    + It can be accessed via the route /custom-page +

    +
    ) } ``` -Of course this is purely a recommendation, if you would prefer to roll your own css-in-js solution in with your custom component please feel free to! Although this may require additional configuration outside of the scope of this guide. - -x> **Not all Next.js exports are available:** Keystone **only** supports the page component as a default export in the pages directory. This means that unlike with Next, auxillary exports such as `getStaticProps` and `getServerProps` are not supported. +Using `emotion` for styling is purely a recommendation, if you would prefer to use another css-in-js or css solution for your custom component please feel free to. This may require additional configuration currently outside of the scope of this guide. export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/custom-fields.mdx b/docs/pages/docs/guides/custom-fields.mdx index 5861be45495..8ccae1ba737 100644 --- a/docs/pages/docs/guides/custom-fields.mdx +++ b/docs/pages/docs/guides/custom-fields.mdx @@ -29,7 +29,7 @@ import { fieldType, schema, orderDirectionEnum, - legacyFilters, + filters, FieldDefaultValue, } from '@keystone-next/types'; @@ -58,6 +58,7 @@ export const myInt = })({ ...config, input: { + where: { arg: schema.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, create: { arg: schema.arg({ type: schema.Int }) }, update: { arg: schema.arg({ type: schema.Int }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, @@ -65,18 +66,6 @@ export const myInt = output: schema.field({ type: schema.Int }), views: require.resolve('./view.tsx'), __legacy: { - filters: { - fields: { - ...legacyFilters.fields.equalityInputFields(meta.fieldKey, schema.Int), - ...legacyFilters.fields.orderingInputFields(meta.fieldKey, schema.Int), - ...legacyFilters.fields.inInputFields(meta.fieldKey, schema.Int), - }, - impls: { - ...legacyFilters.impls.equalityConditions(meta.fieldKey), - ...legacyFilters.impls.orderingConditions(meta.fieldKey), - ...legacyFilters.impls.inConditions(meta.fieldKey), - }, - }, isRequired, defaultValue, }, @@ -94,6 +83,7 @@ The `input` object defines the GraphQL inputs for the field type. ```ts input: { + where: { arg: schema.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, create: { arg: schema.arg({ type: schema.Int }) }, update: { arg: schema.arg({ type: schema.Int }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, @@ -104,6 +94,7 @@ You can also provide resolvers to transform the value coming from GraphQL into t ```ts input: { + where: { arg: schema.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, create: { arg: schema.arg({ type: schema.Int }), resolve: (val, context) => val }, update: { arg: schema.arg({ type: schema.Int }), resolve: (val, context) => val }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }), resolve: (val, context) => val }, diff --git a/docs/pages/docs/guides/document-fields.mdx b/docs/pages/docs/guides/document-fields.mdx index fa27c56962e..9b2b5da7aa7 100644 --- a/docs/pages/docs/guides/document-fields.mdx +++ b/docs/pages/docs/guides/document-fields.mdx @@ -97,11 +97,11 @@ type Post_content_DocumentField { } ``` -To query the content we can run the following GraphQL query, which will return the JSON representation of the content in `allPosts.content.document`. +To query the content we can run the following GraphQL query, which will return the JSON representation of the content in `posts.content.document`. ```graphql query { - allPosts { + posts { content { document } @@ -219,7 +219,7 @@ If you query for the document, the inline relationship block will include the ID "id": "ckqk4hkcg0030f5mu6le6xydu" }, "relationship": "mention", - "children": [{ "text": "" } + "children": [{ "text": "" }] }, ... ``` @@ -229,7 +229,7 @@ To obtain more useful data, we can pass the `hydrateRelationships: true` option ```graphql query { - allPosts { + posts { content { document(hydrateRelationships: true) } diff --git a/docs/pages/docs/guides/filters.mdx b/docs/pages/docs/guides/filters.mdx index 99420a8b3de..869cb8acfe3 100644 --- a/docs/pages/docs/guides/filters.mdx +++ b/docs/pages/docs/guides/filters.mdx @@ -10,25 +10,25 @@ This guide will show you how to use filters to get data you need. ## Scalar Filters -If we want to find all the `Tasks` in our system, we can use the query `allTasks()`. +If we want to find all the `Tasks` in our system, we can use the query `tasks()`. ```graphql { - allTasks { + tasks { id label } } ``` -In general we don't want to grab all the tasks at once, but want to find a particular set of tasks which match a certain condition. -In Keystone we can do this by passing a `where` argument to the `allTasks()` query. +In general we don't want to grab all the tasks at once, but we want to find a particular set of tasks which match a certain condition. +In Keystone we can do this by passing a `where` argument to the `tasks()` query. If we want to find all the tasks with a label equal to `"Hello"` we can write: ```graphql { - allTasks(where: { label: "Hello" }) { + tasks(where: { label: { equals: "Hello" } }) { id label } @@ -39,7 +39,7 @@ Keystone provides a wide range of different filters. If we want to find all thos ```graphql { - allTasks(where: { label_not: "Hello" }) { + tasks(where: { label: { not: { equals: "Hello" } } }) { id label } @@ -50,7 +50,7 @@ The `text()` field type also supports searching for sub-strings within a field: ```graphql { - allTasks(where: { label_contains: "He" }) { + tasks(where: { label: { contains: "He" } }) { id label } @@ -61,7 +61,7 @@ Different field types support different filters. The field `finishBy: timestamp( ```graphql { - allTasks(where: { finishBy_gt: "2022-01-01T00:00:00.000Z" }) { + tasks(where: { finishBy: { gt: "2022-01-01T00:00:00.000Z" } }) { id label } @@ -74,9 +74,9 @@ For more complex queries, you can combine multiple filters, and only those items ```graphql { - allTasks(where: { - label_contains: "He", - finishBy_gt: "2022-01-01T00:00:00.000Z" + tasks(where: { + label: { contains: "He" }, + finishBy: { gt: "2022-01-01T00:00:00.000Z" } }) { id label @@ -94,9 +94,9 @@ The `AND` operater accepts a list of sub-filters, and will only return those ite ```graphql { - allTasks(where: { AND: [ - { label_contains: "H" }, - { label_contains: "ll" } + tasks(where: { AND: [ + { label: { contains: "H" } }, + { label: { contains: "ll" } } ] }) { id label @@ -110,9 +110,9 @@ The `OR` operater accepts a list of sub-filters, and will only return those item ```graphql { - allTasks(where: { OR: [ - { label_contains: "H" }, - { label_contains: "ll" } + tasks(where: { OR: [ + { label: { contains: "H" } }, + { label: { contains: "ll" } } ] }) { id label @@ -120,6 +120,22 @@ The `OR` operater accepts a list of sub-filters, and will only return those item } ``` +### NOT + +The `NOT` operater accepts a list of sub-filters, and will only return those items which don't match the conditions. +You'll generally only pass a single filter to `NOT` rather than a list but if you do a pass a list, they're `AND`ed together. + +```graphql +{ + tasks(where: { NOT: { + label: { contains: "H" } + } }) { + id + label + } +} +``` + ## Relationship Filters As well as filtering by scalar fields, you can also filter against relationship fields. @@ -133,7 +149,7 @@ For example, to find all the tasks where the task is assigned to a used named `" ```graphql { - allTasks(where: { assignedTo: { name: "Alice" } }) { + tasks(where: { assignedTo: { name: { equals: "Alice" } } }) { id label } @@ -142,13 +158,13 @@ For example, to find all the tasks where the task is assigned to a used named `" ### Many -If you have `many: true` configured on the relationship field, then you can find items based on whether `some`, `none`, or `all` of the related items match a `where` filter using the fields from the related list. +If you have `many: true` configured on the relationship field, then you can find items based on whether `some`, `none`, or `every` of the related items match a `where` filter using the fields from the related list. For example, to find all the people which have `some` posts with the label `"Hello"`, we can run the following query: ```graphql { - allPeople(where: { tasks_some: { label: "Hello" } }) { + people(where: { tasks: { some: { label: { equals: "Hello" } } } }) { id name } diff --git a/docs/pages/docs/guides/hooks.mdx b/docs/pages/docs/guides/hooks.mdx index b76871e50a1..fbfb9eff43e 100644 --- a/docs/pages/docs/guides/hooks.mdx +++ b/docs/pages/docs/guides/hooks.mdx @@ -27,7 +27,7 @@ export default config({ hooks: { afterChange: ({ operation, updatedItem }) => { if (operation === 'create') { - console.log('New user created. Name: ${updatedItem.name}, Email: ${updatedItem.email}); + console.log(`New user created. Name: ${updatedItem.name}, Email: ${updatedItem.email}`); } } }, @@ -209,7 +209,7 @@ export default config({ validateInput: ({ addValidationError, resolvedData, fieldPath }) => { const email = resolvedData[fieldPath]; if (email !== undefined && email !== null && !email.includes('@')) { - addValidationError('The email address ${email} provided for the field ${fieldPath} must contain an '@' character); + addValidationError(`The email address ${email} provided for the field ${fieldPath} must contain an '@' character`); } }, }, diff --git a/docs/pages/docs/guides/relationships.mdx b/docs/pages/docs/guides/relationships.mdx index 0708baa3d5b..cd5ac552c5e 100644 --- a/docs/pages/docs/guides/relationships.mdx +++ b/docs/pages/docs/guides/relationships.mdx @@ -54,8 +54,8 @@ In Keystone it’s possible to define relationships from one, or both sides of t Our example above is one-sided: the `Post` list relates to the `User` list via the `authors` field. This kind of relationship will let us query for the `authors` of a post in our GraphQL API like so: ```graphql -Query { - allPosts { +query { + posts { title content authors { @@ -86,8 +86,8 @@ export default config({ fields: { title: text(), content: text(), - // relates authors to posts - authors: relationship({ ref: 'User.posts', many: true }), + // relates authors to posts + authors: relationship({ ref: 'User.posts', many: true }), }, }), }), @@ -101,8 +101,8 @@ In the example above we added a `posts` field to the `User` list, and changed th Now that our relationship is two-sided we can query all the posts written by each user like so: ```graphql -Query { - allUsers { +query { + users { name posts { title diff --git a/docs/pages/docs/guides/testing.mdx b/docs/pages/docs/guides/testing.mdx index 0436857190e..e70afacb7e0 100644 --- a/docs/pages/docs/guides/testing.mdx +++ b/docs/pages/docs/guides/testing.mdx @@ -109,8 +109,8 @@ runner(async ({ context }) => { // Create some users const [alice, bob] = await context.lists.Person.createMany({ data: [ - { data: { name: 'Alice', email: 'alice@example.com', password: 'super-secret' } }, - { data: { name: 'Bob', email: 'bob@example.com', password: 'super-secret' } }, + { name: 'Alice', email: 'alice@example.com', password: 'super-secret' }, + { name: 'Bob', email: 'bob@example.com', password: 'super-secret' }, ], }); @@ -129,7 +129,7 @@ runner(async ({ context }) => { .withSession({ itemId: bob.id, data: {} }) .graphql.raw({ query: `mutation update($id: ID!) { - updateTask(id: $id data: { isComplete: true }) { + updateTask(where: { id: $id }, data: { isComplete: true }) { id } }`, diff --git a/docs/pages/docs/guides/virtual-fields.mdx b/docs/pages/docs/guides/virtual-fields.mdx index 4eae2e7be9a..e1a697ee4f7 100644 --- a/docs/pages/docs/guides/virtual-fields.mdx +++ b/docs/pages/docs/guides/virtual-fields.mdx @@ -42,7 +42,7 @@ We can now run a GraphQL query and request the `hello` field on one of our `Exam ```graphql { - Example(where: { id: "1" }) { + example(where: { id: "1" }) { id hello } @@ -52,7 +52,7 @@ We can now run a GraphQL query and request the `hello` field on one of our `Exam which gives the response: ```javascript -{ Example: { id: "1", hello: "Hello, world! } } +{ example: { id: "1", hello: "Hello, world! } } ``` The value of `hello` is generated from the `resolve` function, which returns the string `"Hello, world!"`. @@ -170,9 +170,9 @@ type Post { We can now perform the following query to get all the excerpts without over-fetching on the client. -``` +```graphql { - allPosts { + posts { id excerpt(length: 100) } @@ -284,7 +284,7 @@ export const lists = createSchema({ where: { id: item.id.toString() }, query: `posts( orderBy: { publishDate: desc } - first: 1 + take: 1 ) { id }`, }); if (posts.length > 0) { diff --git a/docs/pages/ds.tsx b/docs/pages/ds.tsx index ce07fabddf5..b47d461d437 100644 --- a/docs/pages/ds.tsx +++ b/docs/pages/ds.tsx @@ -576,7 +576,7 @@ Some code...`} {`{ - allPosts (first: 2, where: { title_contains: "content" }) { + posts(take: 2, where: { title: { contains: "content" } }) { title author { name @@ -587,7 +587,7 @@ Some code...`} {`{ "data": { - "allPosts": [ + "posts": [ { "title": "How structured content gives you superpowers", "author": { diff --git a/docs/pages/index.tsx b/docs/pages/index.tsx index c4a6f18f522..47f7c55c695 100644 --- a/docs/pages/index.tsx +++ b/docs/pages/index.tsx @@ -565,8 +565,8 @@ export const lists = createSchema({ {`{ - allPosts (first: 2, where: { - title_contains: "content" + posts(take: 2, where: { + title: { contains: "content" } }) { title author { @@ -580,7 +580,7 @@ export const lists = createSchema({ {`{ "data": { - "allPosts": [ + "posts": [ { "title": "How structured content gives you superpowers", "author": { diff --git a/docs/pages/updates/new-graphql-api.mdx b/docs/pages/updates/new-graphql-api.mdx new file mode 100644 index 00000000000..47c6b0afc89 --- /dev/null +++ b/docs/pages/updates/new-graphql-api.mdx @@ -0,0 +1,405 @@ +import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Emoji } from '../../components/primitives/Emoji'; + +# A new & improved GraphQL API + +As we move closer to a _General Availability_ release for Keystone 6, we've taken the opportunity to make the experience of working with Keystone’s GraphQL API easier to program and reason about. + +This guide describes the improvements we've made, and walks you through the steps you need to take to upgrade your Keystone projects. + +!> If you get stuck, or want to discuss these changes, reach out to us in the [Keystone community slack](https://community.keystonejs.com/). + +## Example Schema + +To illustrate the changes, we’ll refer to the `Task` list in the following schema, from our [Task Manager](https://github.com/keystonejs/keystone/tree/master/examples/task-manager) example project. + +``` +export const lists = createSchema({ + Task: list({ + fields: { + label: text({ isRequired: true }), + priority: select({ + dataType: 'enum', + options: [ + { label: 'Low', value: 'low' }, + { label: 'Medium', value: 'medium' }, + { label: 'High', value: 'high' }, + ], + }), + isComplete: checkbox(), + assignedTo: relationship({ ref: 'Person.tasks', many: false }), + tags: relationship({ ref: 'Tag', many: true }), + finishBy: timestamp(), + }, + }), + Person: list({ + fields: { + name: text({ isRequired: true }), + tasks: relationship({ ref: 'Task.assignedTo', many: true }), + }, + }), + Tag: list({ + fields: { + name: text(), + }, + }), +}); +``` + +## Query + +We’ve changed the names of our top-level queries easier understand. +We also took this opportunity to remove deprecated and unused legacy features. + +### Changes + +| Action | Item | Before | After | +| ---------------------------------------------------- | -------------------------------------------------------------- | ----------------- | -------------- | +|   Renamed | Generated query for a single item | `Task()` | `task()` | +|   Renamed | Generated query for multiple items | `allTasks()` | `tasks()` | +|   Renamed | Pagination argument to align with arguments provided by Prisma | `first` | `take` | +|   Removed | Legacy `search` argument | `search` | `where` | +|   Removed | Deprecated `sortBy` argument | `sortBy` | `orderBy` | +|   Removed | Deprecated `_allTasksMeta` query | `_allTasksMeta()` | `tasksCount()` | + +!> We’ve also changed the format of filters used in `TaskWhereInput`. See [Filter changes](#filters) for more details. + +### Example + +```graphql +// Before + +type Query { + allTasks( + where: TaskWhereInput! = {} + search: String + sortBy: [SortTasksBy!] + @deprecated(reason: "sortBy has been deprecated in favour of orderBy") + orderBy: [TaskOrderByInput!]! = [] + first: Int + skip: Int! = 0 + ): [Task!] + Task(where: TaskWhereUniqueInput!): Task + _allTasksMeta( + where: TaskWhereInput! = {} + search: String + sortBy: [SortTasksBy!] + @deprecated(reason: "sortBy has been deprecated in favour of orderBy") + orderBy: [TaskOrderByInput!]! = [] + first: Int + skip: Int! = 0 + ): _QueryMeta + @deprecated( + reason: "This query will be removed in a future version. Please use tasksCount instead." + ) + tasksCount(where: TaskWhereInput! = {}): Int + ... +} + +// After +type Query { + tasks( + where: TaskWhereInput! = {} + orderBy: [TaskOrderByInput!]! = [] + take: Int + skip: Int! = 0 + ): [Task!] + task(where: TaskWhereUniqueInput!): Task + tasksCount(where: TaskWhereInput! = {}): Int + ... +} +``` + +## Filters + +The filter arguments used in queries have been updated to accept a filter object for each field, rather than having all the filter options available at the top level. + +An example of a query in the old format is: + +```graphql +allTasks( + where: { + label_starts_with: "Hello", + finishBy_lt: "2022-01-01T00:00:00.000Z", + isComplete: true + } +) { id } +``` + +Using the new filter syntax, this becomes: + +```graphql +tasks( + where: { + label: { startsWith: "Hello" } + finishBy: { lt: "2022-01-01T00:00:00.000Z" } + isComplete: { equals: true } + } +) { id } +``` + +There is a one-to-one correspondence between the old filters and the new filters, so you can make a simple systematic set of changes to bring your filters up to date. + +?> **Note:** The old filter syntax used `{ fieldName: value }` to test for equality. The new syntax requires you to make this explicit, and write `{ fieldName: { equals: value} }`. + +!> See the [Filters Guide](/docs/guides/filters) for a detailed walk through the new filtering syntex. + +!> See the [API docs](/docs/apis/filters) for a comprehensive list of all the new filters for each field type. + +## Mutations + +All generated CRUD mutations have the same names and return types, but their inputs have changed. + +- `update` and `delete` mutations no longer accept `id` or `ids` to indicate which items to update. We now use `where` so you can select the item based on any of its unique fields. +- The **types** used for `create` and `update` mutations [have been updated](#input-types). +- All inputs are now **non-optional**. + +#### Create mutation + +| Before | After | +| ----------------------------------------------- | ------------------------------------------------ | +| `createTask(data: TaskCreateInput): Task` | `createTask(data: TaskCreateInput!): Task` | +| `createTasks(data: [TasksCreateInput]): [Task]` | `createTasks(data: [TaskCreateInput!]!): [Task]` | + +```graphql +// Before +mutation { + createTask(data: { label: "Upgrade keystone" }) { + id + } +} + +mutation { + createTasks( + data: [ + { data: { label: "Upgrade keystone" } } + { data: { label: "Build great products" } } + ] + ) { + id + } +} + +// After +mutation { + createTask(data: { label: "Upgrade keystone" }) { + id + } +} + +mutation { + createTasks( + data: [ + { label: "Upgrade keystone" }, + { label: "Build great products" } + ] + ) { + id + } +} +``` + +#### Update mutation + +| Before | After | +| -------------------------------------------------- | ------------------------------------------------------------------------ | +| `updateTask(id: ID!, data: TaskUpdateInput): Task` | `updateTask(where: TaskWhereUniqueInput!, data: TaskUpdateInput!): Task` | +| `updateTasks(data: [TasksUpdateInput]): [Task]` | `updateTasks(data: [TaskUpdateArgs!]!): [Task]` | + +```graphql +// Before +mutation { + updateTask(id: "cksdyag9w0000pioj44kinqsp", data: { isComplete: true }) { + id + } + + updateTasks( + data: [ + { id: "cksdyaga50007pioj1oc37msr", data: { isComplete: true } } + { id: "cksdyj6wd0000epoj0585uzbq", data: { isComplete: true } } + ] + ) { + id + } +} + +// After +mutation { + updateTask( + where: { id: "cksdyag9w0000pioj44kinqsp" } + data: { isComplete: true } + ) { + id + } + + updateTasks( + data: [ + { where: { id: "cksdyaga50007pioj1oc37msr" }, data: { isComplete: true } } + { where: { id: "cksdyj6wd0000epoj0585uzbq" }, data: { isComplete: true } } + ] + ) { + id + } +} +``` + +#### Delete mutation + +| Before | After | +| --------------------------------- | ------------------------------------------------------ | +| `deleteTask(id: ID!): Task` | `deleteTask(where: TaskWhereUniqueInput!): Task` | +| `deleteTasks(ids: [ID!]): [Task]` | `deleteTasks(where: [TaskWhereUniqueInput!]!): [Task]` | + +```graphql +// Before +mutation { + deleteTask(id: "cksdyaga50007pioj1oc37msr") { + id + } + + deleteTasks(ids: ["cksdyjrbj0007epojilbv3d6k", "cksdyjrbp0014epoja2uddwl1"]) { + id + } +} + +// After +mutation { + deleteTask(where: { id: "cksdyag9w0000pioj44kinqsp" }) { + id + } + + deleteTasks( + where: [ + { id: "ckrlp28lf001908lu9tyzxhuq" } + { id: "ckroflp7h0019t9lulhw6pggp" } + ] + ) { + id + } +} +``` + +## Input Types + +We’ve updated the input types used for relationship fields in `update` and `create` operations, removing obsolete options and making the syntax between the two operations easier to differentiate. + +- There are now separate types for `create` and `update` operations. +- Inputs for `create` operations no longer support the `disconnect` or `disconnectAll` options. These options didn't do anything during a `create` operation in the previous API. +- For to-one relationships, the `disconnect` option is now a `Boolean`, rather than accepting a unique input. If you only have one related item, there's no need to specify its value when disconnecting it. +- For to-many relationships, the `disconnectAll` operation has been removed in favour of a new `set` operation, which allows you to explicitly set the connected items. + You can use `{ set: [] }` to achieve the same results as the old `{ disconnectAll: true }`. + +### Example + +```graphql +// Before + +input TasksUpdateInput { + id: ID! + data: TaskUpdateInput +} + +input TaskUpdateInput { + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: PersonRelateToOneInput + tags: TagRelateToManyInput + finishBy: String +} + +input TasksCreateInput { + data: TaskCreateInput +} + +input TaskCreateInput { + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: PersonRelateToOneInput + tags: TagRelateToManyInput + finishBy: String +} + +input PersonRelateToOneInput { + create: PersonCreateInput + connect: PersonWhereUniqueInput + disconnect: PersonWhereUniqueInput + disconnectAll: Boolean +} + +input TagRelateToManyInput { + create: [TagCreateInput] + connect: [TagWhereUniqueInput] + disconnect: [TagWhereUniqueInput] + disconnectAll: Boolean +} + +// After + +input TaskUpdateArgs { + where: TaskWhereUniqueInput! + data: TaskUpdateInput! +} + +input TaskUpdateInput { + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: PersonRelateToOneForUpdateInput + tags: TagRelateToManyForUpdateInput + finishBy: String +} + +input TaskCreateInput { + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: PersonRelateToOneForCreateInput + tags: TagRelateToManyForCreateInput + finishBy: String +} + +input PersonRelateToOneForUpdateInput { + create: PersonCreateInput + connect: PersonWhereUniqueInput + disconnect: Boolean +} + +input PersonRelateToOneForCreateInput { + create: PersonCreateInput + connect: PersonWhereUniqueInput +} + +input TagRelateToManyForUpdateInput { + disconnect: [TagWhereUniqueInput!] + set: [TagWhereUniqueInput!] + create: [TagCreateInput!] + connect: [TagWhereUniqueInput!] +} + +input TagRelateToManyForCreateInput { + create: [TagCreateInput!] + connect: [TagWhereUniqueInput!] +} +``` + +## Upgrade Checklist + +While there are a lot of changes to this API, if you approach the upgrade process systematically your experience should be pretty smooth. If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com/) to get the help you need. + +?> Before you begin: check that your project doesn't rely on any of the features we've marked as deprecated in this document, or the `search` argument to filters. If you do, apply the recommended substitute. + +1. Update top level queries. Be sure to rename `Task` to `task` and `allTasks` to `tasks` for all your queries. +2. Update filters. Find and replace all the old Keystone filters with their new equivalent. +3. Update mutation arguments to match the new input types. Make sure you replace `{ id: "..."}` with `{where: { id: "..."} }` in your `update` and `delete` operations. +4. Update relationship inputs to `create` and `update` operations. Ensure you've replaced usage of `{ disconnectAll: true }` with `{ set: [] }` in to-many relationships, and have used `{ disconnect: true }` rather than `{ disconnect: { id: "..."} }` in to-one relationships. + +!> Finally, make sure you apply corresponding changes to filters and input arguments when using the [List Items API](docs/apis/list-items). + +--- + +That's everything! While we acknowledge that API changes are an inconvenience, we believe the time spent navigating these upgrades will be offset many times over by a more fun and productive developer experience going forward. + +export default ({ children, ...props }) => {children}; +export { getServerSideProps } diff --git a/docs/public/assets/guides/custom-admin-ui-pages/custom-page-completed.png b/docs/public/assets/guides/custom-admin-ui-pages/custom-page-completed.png new file mode 100644 index 0000000000000000000000000000000000000000..52ba2d2df316bed7556a84ad3bd8be11a0c8ce1f GIT binary patch literal 38028 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 We0tM#fLHi1FnGH9xvXnd++Cc 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 G9yBI0at%1znRI)c+!m*!O?xW!v004N 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 literal 0 HcmV?d00001 diff --git a/docs/public/assets/guides/custom-admin-ui-pages/custom-page-with-styled-header.png b/docs/public/assets/guides/custom-admin-ui-pages/custom-page-with-styled-header.png new file mode 100644 index 0000000000000000000000000000000000000000..80fc2092c07b3911221a621ca433e83416f62367 GIT binary patch literal 34145 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 literal 0 HcmV?d00001 diff --git a/docs/public/assets/guides/custom-admin-ui-pages/header-prop.png b/docs/public/assets/guides/custom-admin-ui-pages/header-prop.png new file mode 100644 index 0000000000000000000000000000000000000000..6da7fde25b8cff061e5603491d2d9cb6c9ab55bb GIT binary patch literal 9690 zcmd^l1y>wR6E5!V?gZDMiv_npaJNMlcemi~K?1?uNrJmOEE1d`A-KDTyLlz=ckcZO zcg~reo~e4Os;hf?X6o4}6=hj;6cQ9DC@6G!IVm+LC>Rn*TLB3H^7~x&d3z-shD6{_|$*`mc#J$zvwX2sm!vcaEpiSZR_UnDVDuj@<;@WWm3|S@9wU`6Mr1Yy&=Kl$3e^#<2`{zysDojE4B`R|a_v~v0JhGtt z4;339)2m7gP0UTqhr6LrTq6&_{N2D2#=#&g7PyD$(UhPdCPL~otnTi*E!g2oBrZ*I z1caO|G&Dq0RGb)`O$?K#LA6hoc5pyfM=KMP?3i}3NoHfHRt3~b{NLIBhbmT3Sl%SX)Z6qk@2x}-fNDCUW|IR!V6l`)h6e8q^ z1KFkWVE&cDkmSMs+lEs3tthT8DK8H>s++l3SU9+X9NqE}ypAEJ=Bzbz+;o)Q0?Zuk z*@5PcrWWj8_D;VcP{LjSNYmcJ4M^o>Z|C3&@Dic|qj*<$M zq@#-k6)!svJ131O3KbQVu#34RKut>KA2{Spga+j1<^pu)ee0#vNMEbMfotnDG`f%p*ReJvpTm;V1F z`Oo9uNKID@7fDBZ2+&RRzx@6K{$Jt$4gAZc?td=%dH&bq{|Np83UmDK`2Qs0?=1gy z6_RFA6k(1(Lnew+#Z$Zo1x14?FD0(w1$~^2=!Z8zI22f(_(l#UG!$y4XA0X|K^^Wx z0ZedNpmlVxsdjWU6^vRzC`K?3ssu>w0}VM-4-|7p%+(tdxS5m}->+>=zCl!pif_k# zbHQszlaMXoH2MB}7Qd^qwK*0pjKmuxBxq_XxX?EQSWc6{fMSK;C-1SaeoGi(Xn1~x z{C93n42?~q8?MDn@CPRa8n*h^#Cxn^ZV2KFTD1o29~+TViQs?CK^!Goz)6A3iS^2L z{&5Qtt9%w4bc`R@>Z2PYvZ3j1H2Y1ml#Nfw}D(?6Iuq2YcA|Hh0I z#7avgK|403Fz^TS9tr&(?eA{>4n3H9)yq$0ugT ziFcCJ{0v?#&}%1?Afp*%u%?T%+ibDupP;*Y;6BX^lWFcoUdk_e^TJ!xk<935Fampi z^scI@?|U%O(J;!ff6CogYiUK z$aFNx)f6Zbuk)qgy*YJ489(OQrP-V!9~ zE)v6LKX?9TD!9-=NA!bOOE;6r>py33hRb?2hl=2_0(7W~UR^pNXYcwcyC*~_FoDMx zgo#-B?6#YYY9g-TWAHoHlo)0>?fDbFMk4=7oM6&>$IyY6?Yk&jeOrfEVAg0 zViecfbAX6+uoo+1Z^C_t{N9HA2@W=c}f^-s)N`)#^!S=5W8IOZ3Kxj5RC9G z*r1QJEnh~J07EYV_X`X0>pnT%y&N<%0qIN2Jqm0s+FKJ2<;d>y!sXc18#a;i?H804 z8~LIeJ_;|4X>FY|D9w=7&!#3^E8a^ZWI@pCg>|4u_cNqSpyZBhp#f0a?=~tI2?I8| z==aSV^a6Q)BBA5QQ+#pgxJmr?7O!kKDXK1z=?CJ6O zOL1ihM_c&)%6KKaC zr#iiiFT;_g$Isr=ZTyPk;ayjuq{@Ci)~7IO#a#Dw3#I%5&+ zM&}9Jt~Np1MuFg))xe{bT(iu5tQIo_pBY!x^-`&DE>;PekPzWx5lo(=o;F z2T(xnQc6T(_ni;Jb%|fpg*j;3jwM>{ZMYz+blZBzG*4KZ^Yi$`XPw5AaDZEZO41VL zT~F84#CnzX3w8v(kfX`V2;J)LX*5B@<<=4c{ANDttrFrEmp^*BwNE&du@#)>>j;bH z3r{O)n&5c~AnD8i;Wli&Z>(VeJ}?5;X-AD4#Ycd4Pn6&9AsDm$!q%^(wk6!%cft|< z98Y5Ac?{{pxo001v(=*Xg-@tMN69;*WZOdyNbS2(@og?eSY+kM@H+*Y zi!AB7gC+siH9y$W{a+Ta23$p1m`_Xr^c~~^sgYAk&WrNked%L64G~I!nA%2~MfC#4 z3Q`UYi9W^u2baHRJdGO0u|6CD_P-(1lyN^XQmkR>l9|a-5U7FlFg9t z8j$wdk;dRjQ3e_gu^t-2oa{oyCO!_~C!0fiC(*gW>)DS`Zt5M{>TMOHX~g5tf)fYN8Kod}}0zxFd#-xdRha5Aq_fU=)5gof?1oa25kF+bU1z#a#3rUgMH3ioV&n2o1M zeILJCjTBQx?6%!V>^%vVy_g)YUaLTojtxn=31&DKnQ2jYMx76h9b2(z-7T!co=cae zc_M=uA`7aa1`!3ep}AAXGJwpDKkNEvF04l=}+HcW?23CkD7{}8^8%lFs zoWH&(nS1#N=KF;C-5pBcuzz|d?q<$R@pwn(0f$)Nrb>8+?<~`A;X~mwzeHNIb<7v0 z;qS_?<`-N8J(}(kB6PjkN6^10C1b)x$W#3hb5l0O>8A!xGKi~Qd&qFG#yJRyc{|$m zo38Oph(ty{}io1o~`nT;z#XlpxKFMzJU7y$8~YN z%^Vev<2+G=jn-F|A;hlZwHS2LrXSrseNH8T!T6);k_irA>TaT)RSpf-Q@` z?`f*|poJkkHn^>gFU0lq^zm%A!WawNnHW<<12Y>SY+XrPdJK61VZ?;VI7S&iOT$=XeX172^=<%0{qrzeA9xl4Eff&i?<93SRyD*Q{FYm z)QnN)K}%lqdNs;-qn7B6S41_=p}=?wPuWD`gDo3RzxktBBXqXO_2j+2@LtquxtXPY z6aU&Po_YOnQ2_6S#%^B%s7J_;v)B>)8)Kn2{4!cgW#!sJ$`Xg7S>*@Qkfo(IR?dg~e)}X<66u`jeG#E26R1Y0t9A&QuJbyi0>=JAOOY zI|gp7`pfq5!V4tzlY@7 z2AhV!L}9}4lrT4hhvfJ2G_{0cne4n+(glU5AI35c4Db@>aX&lbN{wK_v?M|yLYA7W zr~`MBr1UKWw`8M1uo9icYogf)ey0UnogC)FlE**NhW=PGU0s zr0Wq>Clt66vTNiO1s6_GI!IWp*P&(jXudL^!3~T>k%%kKTjm&2(zu_<>LRI{21j5AvH7HRDDvJp@=3QUf-*pr_JUz1V z75ZM0$QlK?-Tr7sE0q125xjvvO@yPc(hG_%6|RZdd`@m*FQGi>f_Gd=;n zLIH2l#k*UJfbX@)uTt~7{LG`yiKYhH)3)BAwY}{VwaYnC)@gW+LE9Chsvmp;z3JMP zkOdwc3Lh}w4>F<#BjA$GO%TdjruRqp45+9jgaNa8j(m|3c$?*!;eMgQ`T4caHF*Z4 z;XN>1={FM)jT%LX=VEBn^bM^bf<5;`Elz@{V|#5o!@f5tC29?=N-FikgxN zC7mvQG70OHV)*$ta43Dl-K@Sv*qBN(tMEc;i4+offvn{pIE*P?e1GYFU{jaLUhgzR zM91w=c+R*n&YX1+d0R}4;7&8?6;Rh{+ao}pa-LC`ev<+Oydz;SA2#H^=) zmJfjbQV2}GcO+~u?8<>*K^F>SCw5Jx1^$L<`MU^g5KU#YQ zMKI!k%7Ut4;C)EG>LQ44#kp@fHxpD&(CL1q#c20`!<`tSG<3xr+uC~D-HcgU(mw4% z%Q!DdoDEW0!sGZv_(nW?m)&-EVa8R|U~bJ!rJ?>_l~J;%d_3(%22G(2G>Fuc%a-;7 zP*UBPFgrD=GCpciY4h48XnBA6QtvQ$Z?*kBvr4KdP%D->eA$1p@-aJ#PdZ9BBHLGoBn}2=^fL)Ut3pJfp`>|9xTg$>8-a0~hvQ<-2V^op{liybY8SRFZ zjOtvi)I-VEncj!5$}l|dktGOzVCxuA38cIk9M9?^%EdT{FyslbT)8gnOe4T+(G##DO2*f)nUz8N@?c4i&^=K!O9o=J_teQk{p7~I}6zfUSwt)rDVH8VU z<`dXQo};NzB-YtfV(Um^te;QAhBw#57|t3$_^CMaJ<> z*+e@^l6*?GAcuFf@1~0$AMP`@V_iS(&>GyA`=3ADjr7eO*WR*k1jFFb;wT>PQm4w< z1OicAZ4JM0KnhwXw26r(t+J?IHi0ki#O?*W%-YC^i+^Ah6qqI^g3>yi&XWP_1>Wjt z`P2lB`F*mR!%2l88D}y>K$C23x{=0xlh6LsTVHzaJA?g4h3PsO|El#mReTZGn_eY} zLbFE?1#>6p_^(6)8-{KNGn%PlP8*2|O{a^+Y61Jdez-O^BO3*Vba3~{#!ru`zC}Vs z?>s%gN7bOH<-d5OM8v`;4;z-te4nS^UpzKg!*1oB2B*&NE4VEp>`b?~ps?(-=~6ZM_MgaYQ%_x%dga#H|<8qVwoWw)P269z`$? zrfjAzxg@92d#cmbvd4n=CV(stO0AKeF8N^(x=i?!J74b=kMMP(zsNj*dznLCqAw); z?GHJq^X{SM&gClX!ly6Bj%C1)D{Qnzjgc%E2V9gfe1=0I^*<_r5!PN&(g>u8VbQ~! z!*Y;k1SuQ_8NkjrvGt)UMdM)?PuPR|PT!}08)@ZU|9I87940E-s?KB+M@m{6II3-2 zIgvV;Z#!2J74*C&@%0tvx|_909`Vp1!xF4%hMrH4z|<_Wc%?D!AHjLVq9F}sf>m@qFL#E z&7rVnt_4$0DzOOSg*s^X`aOqcPGU+wXu<#(Y=gm*`Ykg7YRNnM8#=L=>GWGqnqS}C zwz7j>-tRkeQk9(Q#69^cI@aVKBKxmn*0ieAd<;hdButAw%_+3@#dVH+B`+eTF0`IN zjo%XRV#ls#0=ag7V7w|lF0zQW5huxJRF}Y|u(Gy~cCG)cS&x==b{3vb=S**ALdTF`GVs|&bbE%(YxJ~q?7*BiYuW9@^pVomve-7aIsRZCL( zw<9d}EopbXj@O?&OSNQfLk$Y^CMXKoX?J{3X!iLPTU8B4^k-?#Ph#a*H*|T47l+q6 zTfe~(Bw~>W)1r{k0jw-o0qAp`4QIu33Yn&CAr*A`kjjsN)W%T@szAU|sLkg#U(ts& zW6fhs3VY!MNU9Qtk4~?a?$%E<&=gbA2y?R+T(@ zF#A2j*Be@E8@sh%D3$3!V5#KN0nSs22qu02VUW!{Yas@w8;uiX!Hy9C-o2{*6zBrx=NrBFM2Uz@U znA)DM-zzI?Rv|=Tj-_0X+UswoNFzt3+@>F#!~3*g9~)qsb4Zc@9N{D}wNFZtot0){ zbe6+3)`#lf?@Hz}Puf|_Jd*(me8!B-@l@E;)Hv`)s75sCwRkutXv7J^`>8&*raz^c ztJ_Nx%im~~MKI-YwP2OGKlH6=VbD-~ip5H`c!Ai3-sT!%>I?^r0=%R;ON;z;wdVWvov~{*C9E(l6+VwW~8O&K9K7~4hqU|j0w@Ru#G^=!*Mm)xyN$su= z=Ra?UJrg*r?2;P^_1Cq!+g5(R&sPNP89WAxT1#;5Onxdd6#*v zipUl6OfwZ%Ua4tw+Qf+`7jY1plo!IlCgFRB5QBn)9?lTbK|IKc<6A6#Pu7bBJ{sW=i=JLeuG5Gx=JoFr z!zET?0>&xqxho|kHcGQ66ftWJg3ukl&+TSzMBt7Ov&eV6)I zzkf?7x8PO#*pYH!P?r_l59{7}G_CR@?na%dF5z}I29{n~&W3=vIJPNs_6%xUpRGe^#OFl$HjubTiDk5`-F+~s;q8!5&PH5_{=#vLv`SC=Sz8zg!8MWFaEQR7@WML*%|6Hiw%m3)4`^;A-o>G@vkaw+b~3C zzw3Y-;d@q)Q69d(WyzW^BIa#4{Sx2SlKTN4a$7wjRT*8PdMP>zYr5_CI%=8}IoBNH zR&!ccykgEdec*n+(+!x@z4$P3H5lVE@$5liYMmXEfEXCgG;3KwW3`_pLK-;hxX@a> z3?3gVoXDhco5pF-J=|>I@=+sQR7hiuN8TFTxaMCk)#;;azdAVNVI9x$J$@06NhF>f zECc~B;!{MP&23qc467#JW$@q|E9F-A&-wGx0yLLjWf1 zw!8$ixm9w5XlLa_ps|YOrrj%3`sdFLHC1c7(v^CN5wx^PpVPJWk8YLdGX1?M z#pu?vgODmwRdn1nUmrvDw;bQB)m6!LDZ_F`sb6*I1w$R2F=3~Cs zdp-~FYcYY6;0PfvdbK_;`pKxRVC(CdOp{ai7&HnPpZ6t)%30iN4(D}g3A}xGiPNKn zeG3e9gM|UlJ~~%@c5Q&TR>$--B(!e+*QFKGJ$C_i^ok$4tB7$`Yu@g!7(UcyyB35= z)f;i*DuIMqu&0GtKJ>%-^2C07#W?H=Tv-5H{qXQe_wk*fQH6CeI@^e(=gLq%$K|61 z&YY`)vjR*eJd8a4B2K+OKzT~G&r7{|-}T)llX!DuiCH!wJCsF9%mUi9iYrO=-gjcR z88I-hE3hiJbc-VYE^-u~WwE5y(hYpM%Te$K`W+r~5!+&hYKzdw?q(*D9{aP$SnayJ zh_2xvwIo9rBNAtHgxq3Q{*Vz-m$#{su3eo~RB@d99qsF(PC6c!g8M0s#MY$6@mw&n zG*e^#JADqlL^}BgO%rXEN#p;YkxpsG|d-crpXdcy_|Ck2+2-k8miL{g_@AD)BO0RdM9R z`j#?jqx?h14pYEj5Rxp-+O@>|q1O{hkp%4a==g=J>Q(=c^20{IiTw1YRi%Ib9*{!= zVb$Mte7~ssmsbCh4q?fUw%I)YWUcf!cdzc)BwY1xtVi?^l&|;L_kZd6pG*+L7vEOc zFj;;NDui>V@ZQItgZQIt@dp~=>&%4g~{rxy=om?v` zqaxx)+!+}WbzK=1A}1pX2aN>{1Ox;pE+(V^1O$Bcl^%lx|N1Py%l`S5A!sHjC?_r` zNFZl#V{B$=1O!A8W1y>xEKWl)tf!}|J3K*632pD9@cVbTg09bKcTe|d_el06K~l1& z<`xFx7N}A$P@a5GlLc%z!AmXOFb%@-t~uJIeV7MN`x2JsW_hnt6iBmzLRg&d9X^4K zG#v%imsTm@+JrGlX#O*J0*!pgBMJf!_}>}udNx2caRg_?x~zl(ll%{G1R4aK#7L&# zyD$VA)I75VEF z$_Dwj6!kCK1&2pKsT*qhlpn%P(r{H0e<-^R(2hluDeL;rL9 z$4?_yv;SJMcKD}RUk#-HtAw7Bj)DGvbbpBg{>tT&GjlbvR1-3@`U=mN4PF*bCcxkI z|6e8lwfG-NWd|dBK^v@Ag;qht{I<63=8MkHOYX~u_0EpRjSk63C+|nMrnWlfI_Axk zjLkQF^7;SBaqjc7;!I3x!z zxKX_DI0y(M4*OsvMPw9|vva(Z<#n`36b%7Ip2T0mzJ4LU441yuY1L|$+8WQ~q*KXf zFe%%cv*O%nep&j`GYKgc^v=AcA1wuI`3 zEW|0=f148n!@~w6>GQTsrRvD8R+k*%!bNZ+`&-`!4CG!Z-0H?i%&4;|xoumc+bVHS zmFME*+nQ2qjRATA3E93RrkqXJXu@!rBc=WQEy`3l3{=h$1Omm;IHv)p1dFwp3j*$l ze99JFrZNOGgsLjlN+Ij>oCW{I{%FYIkY<;R-cZzxf7hd&J&vKX_&=?bi$=0N+TDM* zvqqKEThLV#udzdQ-Z!^4Oxp)|QY)iM&DN>Ohc>&#DJUw`ri-c|yCzYRl2K-oN=E0U zr7==Yu7iRMM~%gy;tGE#Q^m1oL1ge6gvVvXL5x?&)kXj5k{2w!S>d>;)C$h6)Gmw$ zg`l{3bE|c6&LukMR)|@!qF^LR*1y~s`%x*>!JE!sA})?F@4% z+Akgh;LFNTcgt{N+S8~dA?+Vjkf?o5w6k*|N6^6!jT)qKyET-=q4)8zw{^_U4*;u6 z+43GRmZms*fvbBo%KqwESFXg-)X0sg>O+A6wT^AKF*$xFN#}pG8LY%!-6+lc)ssw@ zf6TGI-Jn5tI)?1@5%o8O$r9dFS?bP6q^JA&ZEw8ES@D`MoZd`Dpwo(WiB)QAJDP2JTTI*UYr}Xag32;{JX^&K(^qA! zpQIq6_Nn2%TT~3(w7E7b1}Eu|(Pv^%p}Jm!yz{vD#@KP+=2!GBC6&n4=o3lkTf&~} zG$&u^wC9r$YV4rWDW?96@Qh670SLDqZRxHsTCfd>h+y6Jh$}DTqUuRcwPdtO_d2}x zcE}Ny{;6lo*z6eE*&}SqqP&g!>bt+~E&JGp%5NpntSW)8Eg7t&a0t%*&GN!qq=)O& zc14I*+dj`wO05Ici4hOwe1@uj0-7MXlb0pr{F5-5q!>=?bUgJ87b1*5`Ja5dyX_EQ zJ9=-4q0C5-8ob_}%m?DYEasf&Zud^kh10rHWyUtKWg))P|mdBy8y=e4VT!`zE(P6>TdnP(q3k*vl}e5F3u1Ym!U4fc?Ne@?hnBd!-mqi@avD$JlSw$ zd)CCsvPK(8AL$RJy~C*wjEO8f0c&1ffco$3Q_W39jYfI21&aCeRnh+Aj}H%2=TkDP zG^6egmBUD-8es?fhr8UPV1(njAUF_3p~~eF;)F`oB)=skl}dHRm=CZ=q~b?x+s&Fo zE|HBc+10Kr=@7f?oz4QEa~6N4rOB-xlN?{WuY&JPp+aWVBq22lkfUxQo>F)<2;LWHm5SRB3oPCC?0lQ8l#= zw)xp*sz+Hm=*Bfl=5x)l^k7k@TwMrUO3oEsHBM>Cqe z-ObK<%s>z!Ftpa3F2wpg-#Gpzoetx6Q78e2Gd)XH-tm48x-VIro1%z;xXhR>Qaoxn zox6KJES6#CKuj%4?Qoad>u9^XOy~6LaWOv7JJdazl-)guY&3Cu%clk@9&p$ltZ-I74JS*1kdvSKE9O- zi)|inPLIzaMCfu6YQZoj0{RkiJNEjC_WYDz(t}@mHUf3FmV}Bf$vY6XiZj$E1eK$& zn#_s}USk73+!R2FpPp2ym==q&;|6k#m^5cR=b#jexi`@#dfYpS`=j*oWil-{JhGC` zFC?y%yT!E?TloSO!^!m?O+s9v&_C?^^n2Z5v3nAoQoa7S)+sBGh<5`1!$#}8IzS4r zvem4F*t(v}2G|Yi7c`90gcUQ<+{u-?LOeT+`_bMB7 zv04aMB(6a_y(|ex6o{{-jRsAE3x#%mZg*%eAs1zj(;u^m(*y z-rUwnJsW|m{Sv3)8>?^iaimg#K97KZ~G*0V=2x0+C1W_!H^ z?z!_t1Y8nR_^Y-_SXMTo*xV=FPOlqOWz&uHN_@^A67S~KU~pz0kMy@f4@s^&H~o9! zN*x9sE6ktlyTnZ&mm1riE?MXA8Jn(xQe-k#j12EU#>L)7qZqqCxqX?B6RWz!9rjiy zIzi~=Ni(A}ma0QoL1OA(hq8_cW#6_SUH7*LvAWNd+Rf42yT?0z20QE9*SQU{=XUjc z-@KQ09^V^5f{YC4zFZnj82o_F0+*s&YX>a5bpII=Hhh*PijIObOw%)|3NNMfdSDvX zD;0fz!};FziwvPyAbfNC6T0MKPb-JnMaw=sq0Mi992Q*WWUYd z1+bTPtdwuAY_ESvB{m>)f!A!6XpPHj3CkCEu&0(UL2AEtGESu~%k}wsIrw@_!w8|( zDFu91g0RAFLI;;I8_wI}=zD>~H>t3vpVzvUEaqT;J7*^Sd)pr2aR2yJa$hY^p~!{a z*wMN7m^vooiC>0p(vK2DA4RfJ1{K{}cZY32@6w_8d>+h+9TJ%va(q6E-1KYOM_vRr zf|I%&oZj8R`t)12tlM8z-&sjgWlcvE;6Jf6%%V8H6*6u5DEw`Qy~}n#zW$Q-xrX}YavI~Xl*4G78fzw z$smK6y`y^5+p!8Lq0sCE;jB%8-gn%4JGH~xC=axCc0hk0VU+fJFs_q4I$tF__Y?o! zTMbjRty&`tqn)Aqhl{fnOXU~p0n`9(=9^e7Bmf#rO4N@go?sn&H3_%<$ITq}s%A~4 z6&t-<$!@CRYT4!C-deW#BdM#uMr>`un|vg)C3Bd88THYb8!5+_D8z!^3YAe`%s7uU zuGyGBBDz_vpe{uT%}6m+sSaX$n_gCc)*obLlhtG9FkSrcJdbuq>Z21Uy|hMD{B7}T zsKM2e5z0Xah(WCQ^42JeepQUkkcc$OW(U=ihaNDhzRWwhq`nbL5r{D=*FC*R)Tqlb z2zZ65>r45BMk}yBc!MB_8^a+{);tHj`)AO`6o1PQl*wn*GI_;*)sGerkFeP*mRBeK zmRdivO->(yfIbm~QA=@RGGXZDlKWkpX1Br5Vy3c;u^I!Tf<~(W8}!wrc`9$x3MOAM z<4rKuf~$rZJfbxTe7T~&XP!X{WfXkLLsSX9wuaOz8br$}2DEw~Bbqe)oulo9F;vVa zx#HD?rz83YtYDr@6HF*6eAK>&kEf$Map+`EN7v@B0XGJ6j~xU&Plqitb&+ky5_NF~R7?Hy3>OvQLH#wv1$tMSFSb9;JpoiR{dBKq96oLyV>tekNG$8QUnz)ba@ zYY46Ofp1hw3@gz{;Kvjx^OKBv+m2SByxZBTe#)`X^A{^2LEhYgn$Bqq+G1OARH}K) z?+`OtHq{l%15)uUjW~o(zSpX{CEA2y*}w_Z@>la^M3BhF9FnFEnOFjGr3=}+XBglk z8&Ouv(3CUD_7%MP{K2hFnyGgMYhkdS{4z8XzR`Tep1XrPzkO`?{6H}+O9?b~0%}@- z)QW4UH;aA6su(=Qd}AK*F-S!MOTL=~QwFYiwU-ENZuBN*48M~6@|;!b=6Ix2Murgh z148g2tXX3yc%0-rB3nkAgAF zjV03?MeaPeny6nlo`xFXS#XEUri$iHmsCpI)XQc_Cr<{JH*$|fwu75Rj+plP8l41m z7G@96aui2FJ)&C+*C>v`XddwB+)&-CDx%_($1!zYi@w2mKkab z6&TT)55*!mb!U*)dV}EM3kvQJeo|iddkORL%vCEL9C5*A=8hk!qbSG?Jj@}^d7|=g z4`*Ips|RPOeaQ#C2ee9|5L>=FQYibFuZt2nWSdhDW`BwceEvKMLbyVyh*AxPw+m&o z{zwfIyM2Q1u=9s@XzRUQPnbW=W+To*L1vl!<}V?ZALI`%H*zu$c^XUIWIBj9Fi&|E zE8rd^8%%ZWZsr>3qAS`LTJcjJun8k>kPFvBYg+}*yp!8bBAxRC zIIx6VHa8U>j{<`|eS+aQq}e7pfP!P*nBJoQ+qy1_Fk_{UmT{u(h57AU-4AJRw@Y5q zRZSlKomstcQ(y6OI@}hx(?1<7b>B$L#op1>JwPDpWU7+6)HC<-GihE>@MQOb|}E zE|l|hfT5uv_{yDZI9w4E^h|j7rl0RsOHR3MU=p}@{xinaRv@cFmoc2TYyKzzj3pX) zGg!of-go*ORWEUT!_IR>WnJeO;OWlt98F+mvM8Tdu}o~7>(j(>S)d9oRdPAlq0n2h zzB|AVgTgMFbA9A#y{XgNMQy0VB(Y#{V{)|?%9(n9?Y z#qR*K&+id#f!g{aGqy{J=KbODu^$`w-g`!T)I#B#IvCPQJBU7sKYNG*t=|doQfoFLh!qsAJ)}=vGhp zJ)H0gM;mUp;uTzj3M3YGSLIzkDUw#AUHn#RRtO->%UxG4cJSmB=(6;!c4q<2Dj!x^ zoMBw;OhH(%SR{V2JG-V+Q+!3zY{*NuZq&->OCdjRT5UOu*SQ^n$Z_U{*5n$gb@oP7 z_8-nmEK`GkO7~~aXyHHv`^XqcPZvma5_1=&GeksHs*tdcm9|-wxt&pEw2Bt0idIdg zLRd<^vvp1V=`T4xfQ$Ll+hzM8;zGM;)epAx+2)w?+bfmaa-f-ysu@D7E%l(;gkh|^ z&FAy&n^K-6d1*Hat!rb}YHbS7b{ke!V+1bRHrhsbQlsydZxl=P7O6NG9vXcz%=}VYD(v35_4?Z1>1iI3!I21r>`PIOj?bIhmdKHs+EGHT}hPV zvkA&!bJy;sakk5gGQ1^2ZZOh<9`21dcU}ax_utmv59XmJ)VqWDu~cfRHmq+*)!3uX z?RL1dLA)lCo2POPW^8Kk_6#=EL+#H#1%2;0eYRtKG7vlwxlI7v*%l0eRB0L@u8YN z2^NH%A5NKJjSf2Ag#wIb*!4Z_IOO4v^h1RdYH4s}aDM*F8S`ZUSO9ju54{jhs)B)9 z0?GVhSK9R{a}IC=i+x|!wv{@q489qx6jo~n!C5W=LJUwhV}H*4+Hn$QjUC-t6xxIm zog}<`&NQ>jZLIORfSgjIoJhuPGZbXy=4;eAa_Yy4gE6z4Sas~NL}z_CkAX1lw84>q z1gvV#Y$luU4v%+c8~EAjR}8^Wf|ALQ$!V~ryCW7M{N4o77Rb)ts4BdDzq+k55ei<% zB$PhJAo=ZO51?{LkF}$gbd#7kCe?qMn@DDC_p8=fnAiuS^Lco0?igvAG+ow{mV^@{ zxf=e3#SUjrefV$hdca)xwdjuzdvh8}{Db-q^MNs(NxF|C{%Ufy8!5-HQ;8c$_(HQt zKsW{Yna9dJnQ}~d8PAL@lf+XPrc+V6-HlSNR*wh;WX)g z5N86#FFn}ENuBFotH2;Fjpfu3M$zI9z`!=fD@%G^p@01sLOBK8(q^pBYBrPJ>;is{ISIW+Q;*OK9SsQ&+iArCLb|5_{Wxr8`^?k3P|5+et6T4zcAv zy5nsvXwOS=38>I~+F(H%Big>dqKZrKwM=+7MDj7XPXY%IbI|AuhjQ{nPK}k~-ZePZ z*Tnf|aAkDk;Fw!lSvfa35b<_~>!|6W-f%{sdwKk$QrbPA(NM*^ppe0*v1sp)2CC1N zsswbWWc&_4`~|R~PAS`vm*0-;MPd9EV(snS_$0AW>L((IwRh*7^@0@DOgup{h%Ek*Xr=O)Z5#R zq;!c7%c62R_&Vkj;oRKuO2cty$Z;dSI*p&u1zem8$jqdogMa9RW9aKtUYiw2N9Z^M zH80l3e)f8Xo^S07!wXaYE?VZS#+jH82*7PRm6T||qL*B`h{wqix}JuLuQebYIMWuO zjHxj^+!;4};x6ON56A_MA4LI6dPT5LR{Uwd08aAaYEm*03*e#15ks=?a*tT$eh0Wf z3w?PLwj+s39(9ZEKs`1@l!et7tS~EE6x~tBJO!#q@z4V*AtOdGHB(R`)YizdcSOi_ zwJpTeb`&*~%PT>scz#Y%`jhph-8N?P-0lyCq0JfH73}NB6;ga}0?qZ<)WH>%t==ojj;Xg;G==J7rPgtV%SH~H z)k-uELV(A^MNU=cODLP=5`ULH4tH1Y92JZdccHy7^zn>VvDh_`hw&0Hbz+R7=@Rh( zVWXuP^u;?^!q@7cGKqL#IRuY)Itw}M`?p7AD!nKJ(Gi!+4H`b`c4dp&UG%Eq(S(#j zIIHzgXk2a)c=_p+!HEV)hLo*fccy}!37Kti9ZSgNTSL+W%tn7u3yZU-yi)j)c*l1D zvu&rNeo#g%+VwpF~wb(Hlc>~5LdqT9IKaj*BM%f@~H4n^13 z$oN_tdN+J-x=gg5B_TF5nUZjrVP3MJH}-ONnTI+qx`6~rX+o_wMQ95(0gT|c#dqOK zms&Ew7s8-}!NCtudrPy@Eo=-bAg}ihT9%Hjs>0|-hJKB6h!(iF=9$lH!yYuh+Rp*! z-U)z0IjWoD&9hjnoDRoi4#;P5z0&>J<;~;uc0I(BqLaR_m!rhfo$_WSALUR4eZ1no zCYwRf^+hm+<`I9h_wM0wSEv~X!`CVph)b#2LkeU!7ZU&YP&!+D-oro=AB8#der7^I zeyqEj%au%A!r^PR_OkDCv10f*`lIegONQy?M>zQ23Ei@3xB@ki}!%f zFN{u4QdDg_I@%n6bSfy|m5CUq(v`tIk|~|vbIvU%_bKoLv032$r$ef(LiMrWnYaWXE zkq}Mm&HP_o3%@-T)jF`|9-&kuzms~(Uh8H4{QFDzYrq0@|hwP>D0$Kr+~OS4O@Lbh3vHgdm! zYX?IHxp}TZ(P~U&;1ts z`L>^=hF;Eay>+kY^-^kxlvO6i>EyQy?Jrg-j5dM5Cd(XtHs1ksda_K+ zA>-6)_>6v!;KOIDmG1W^m7p5#)v?x2?9KT2EQRI~gUGlW#oiZbN5cK0fMxe^J@7r} z3s|>wUL)6*ga81=uW6x0t8Vi^);+f)AmKVL`oi3vkED|WIwc=ERk~YCOEhLPkKQeq z&~nAE`82VRXe{x!0BNf?sNY>Cwj=LEA?%>%{fTl8{1=OHBfAxZ!RHOoYPR*|O?iWg zB6fE4oy~`9Q3?AcbApITI49TxSe1mNkbhlaSNu?Sye(s^aUJ1R)D+|H17-JdS8Znjc|0 z8wrTSE$l5@9vp2v{1cfmoSA}zVWSj*MMT{`d|fbBU2zlYn%Tng`^fEpg%tg!@Rd08 zdj@))mY5YZihx^OyVvj+C${IdM<9GHL|Ex4o---|OVJw_hd2#!w!2G_FjiQcUw$9+ zYu_i7$^CLgocFop#L+o#iN}I+dj}ZLP>X_f0)i-k+!y|1f4JjSh>FFY4qr6RYa2Np z2XDYmZD3rAiu1SfehWX;faGtNNt-?{M$B;CLI}V3@Q?i-j6AKlB?#hX?lcpY`0f?N z=+%2{GM6=a?ZRKmWx{G|x5lU%4P0)QOCp_V>ehW9H!-73h&_tS(^*^o|bihI!P?HvlD>r4jdN5UN;it5*hEOxDAhOnG48O8fC zw%nhIgzGJdG2B#E7z4lM8d|#`4vJpEv-a2w9$(-}(5PsFnXu87%o4%PP>ug=Q8gTZ z?kTs!ovCBztd0(>8KS)6wUF@$FWTdz%=_Q z-f0VQ*kw}f2>67D9xjxvKb`gyqlvsepMy=Fo7}p!CrVLejbXuGfsNNj0E+$wk|mcW z`=O;gi6$~RBjQTGNna9aHD+cCBqNNbGimhZEe*UWJ=H>?jKn#E3Me#+k1oSTGUk&p z(m{e@^Im0nNHN%Fdarw9u-9BZy$P3fbBRvQw#jOP*nnM|bvl30x!A-pyAVu;B^Cb( ziR;ab-8v-CM`7UHw9-&Zg(SPo6Lr-M%UiNHvZBoV?JrP6QkK*ng-3oEETG>VAc4K- z9Yn58^UXJVW$+C1+=Lbm+*@jtAug!m>l=bjeD2HawHo#9vu6ImMT-1!p;{S>z6!rfr8Hw~WN&r;T%*YrwL26* z2Ic@3po#K6O30*Osw`)$CnC3RUc%Q)2^ZV?`EY)QkNm@%1}?;xxx%`Xh9>hT zb=827n{8jrP)l<+e@}hF*(E-=co~-yN*A_;T3ul->USzs1bb!MNtuc8rf&8kgNRnS zPK_s?F0bHhd+>o8W-aFxBpJhGAnw56k~;LmKM!Oc?ja5qyRmG9GXxc^eo-nwuWWkb z*M^&zkonz^`FL$Dj^E<4MS#BD9~;o<8g_tN=IhwBJ9{Tv&pN}pi$PhkD-KgW<=C4$ zj!GDML>?a3#dkAbZSlSbya+7?YCz$Q8%L}0SrGDBJkpRL^*lg@tP#3|=tu?L zpe~ez$yuOlJYkcf(@8}FvZ=s4=qY^r1RkKu^`(i6Mds^xUWFch?b%cN(^^uSOBgmd zszAo7S_X#Z?h1Vcm z5k^nhG=P+f+~88Fn3@IkCL902DE_P6_2%r3;r-q5z+s?86kD~W@xfEj`}p1kUdjg{ z{_Y?$@x|Z=|F5IAmDb)Y@CQka;h%2vuFJ8iGP}(+&W3yIX+&vr`G%o}aXkgXVaNSb z4#%5OMRFvvsao&vM{H@KKfRy7we<8bQ}@F+nDf^5Wl;f+Coem$Jox08=h&-Pxgy<74xrOpa}ogd=wNBsB4asHtQPV zjx)yAmx(?3(8Izd1JS=sm0AHdeO+H?(KCh7_uKOEE(rD5^N@|RrUG`aTie}kf7Agq z--CtZ8I@>%U&@#@NYLLf6xd<+cDWca^4}@_Y7Ly?)F0W^Duj_(xB5v@SGVYos2z&rEpcQ!) zT-^^`fIIr-kxoV31udDQ8dM{;N+5Q?OE?V(!CnKi(qKhb%W>LfP#pedlwVWTbyNQt zfs3OaO@iE?oI9CSiJJ}qgfd*&zJ}Ezga$`{H{d%#sfd%m;!J4*(b~_{YO)B|mI146 zU2t(6Z&;VHuTCaPnpfl+TgA@F$G`y87u&?bZ58B~2CjBOJg8p1v1BJ>uS$_&{O~0mxVnYm`E$^lXT-?# zV@`}iIExf&1Un0P;!7S%R}w~j4&^AFI<<}S?YInAar-=S9j-+wv~n>&9JzG9*aEM% zdRI)OC$pj5;7-_gMt50aEuz&=+}u3j?}>vNQ5K8+?@~ipNYoym zwX2cvYl{YDi-=@s`yKoppi8v|0$ zDNoGMOLvc8f@m7fY|#(0o)n$#9;s)_ngol6+msdt(#`^6E+FHzk2Llg!6onO+s%G( zj|(}*{ZY)gKu5hI#LSVQL|VaXqtO`ZvPD$CR?<>)G{S^H$5XnwPC1*PdMiO+PzdPD zpT)sBiPA=eDcDL0R`~?3zf>zVQwpWiL}bjIkpj4H2yTvxvJ_ZVbowUY#Ien0iU@ui zWo{9mPE0c8Ot_T*OR`oEh|HJKpY{HMZ`NudO62u@*6T)gIuMYHsh>DB$D&G)UD8Hh zX@TLcF1tKk!j>mZpl)j-8nl49^k9!@7 z1H@SpkqC1T`<54o)2N3w5PG={j)5{U|4EiW6JFO^#ow~=hN`8E{P(*13$ySTZ)I$mrI(=&DzHEgv{Os3cSKn(apq;cO}kL$c=?PksMsw znD@sW@1?NZ264aIVSxU)^OEqkO*(V?Bb;WysS0f&x`xF}8`1_D$5RU2j z^CaM@FZf&B&%H<8r&-jE(uCnr-*>VtP~Q)|$nks8ByN{LE~ff#T^8Z2I2f1Jlp@zY ze-7eyF6b803??|eDJua`O@8PbQ^8)ZzrDV}%EWaDxAd6k!rUfMme=xm1Le$0qt>yEq;(Hc|?qe z!@%1eK+z}HRq9DcJLTv?g@)NozWCh;dDb6(XJ?I4xKkP8>P2wiRUEP*kflC9NVC{nOZ^7SfIOza;oWD7 zMf{rb7knX+V9r;G6M4H~(5G%Rx16nL>@urKgu+hD&HtJD+6-TN=x+pq_6{UHY@uK6rMmw;knlbzPnE z<5i=-RJ)_^*YYSO2p zP{Yt{2PRM>G9bTu4b=8##l8LgoTNsKquInqF7%nNl#kV&V5t&=lfOd zWIRTZkaKx}m;Ado)iFU#PUgV{r5zJa1wdzSXsUltTQWMn?k>F^mH;jdo3H*^qrFi{ z+X=tc(VB6#d|i%BMxLa_s@?K(Fmjy;rMQPs-Cuo`b7}VDabs#`kWxbY7yZi0&a0VG zJ8S!6V^`ZKbDjOTHMifQE=|MSCNp+Yy-`4ar1uF%%(SNeb^NBiUgLbBVr3nz9yKQ5 zgxHc~VR&ZD7=Nm<7m%Gu!&t;X{1Ij~8l8K6J8(cRm2;K=dt*G(D(l=twm-c}8OP(} zFj_7zqH%@v69J~Jd^r|xN%y>DCipgeZdm~zxTs$7035n*uy5{AJ^7lr zgtb;uuQ7dGyVVjDj99YSKEs7$w*pC>Ye&Nmso}oVR(yn$vwT@N2@y0VIEAZLHIhpmupvK0qxI7R@a$ot8Q1bA5?YMb$twTyJtC{Em zOMf-hLMCQC^=f%fJ)!z1x89G&WY$qo&xCih@dWxhmsQQwHP|t0ZewGGaZAma1z<@# zTBJcm?}-Y9M$AUeqPkht;4-|2Iu3U9!qE5%MUFUB4Th;)$FnGDj2jCeW<}65ByE2e zhSh>K=ZzD#i+RgMggBYmLO<7KK)+iAGxPeiM}0QHFp* zpHz?_@YuT@1wV9;7!G0Y@s$Nr+U~{oo#1*L0*GQSep(TlVA6bXYDd6-(Pw``YvKQ; z&pg2Lhl^gx64B!SL(l>95D;KC;{B9g5cp?1hGW#%PK{O@eRY9<=)OOoAhCL z|L#3`{9+|5{x2xmawVA#s=7GJDf}OY36NaFk*aq)ekWWa@eIyK3n%^KcgU|!q-ZKT zucoTrS%|zE?{o7ibzsN$D*U^=K$wHaG$U<^B%CdhM#}|<=#_|7G^8e+S z;J~=w(`mPejHy-@ArFKpbn&haw?(UVqH*%_`YzZki<8S_7Vz?L%lElA+@3Gr2z>Pp z{tF^RWMq*sm5QR@!xZlJ{Pa|ct%eu8{0C%6!vnm8OMNpe6a4%5OEZT-OkvjC$}Xo05Y_({vDvtudfQ?-?M+R*$8Q8W`5rt#cqlEwVOq~ zaKN#MHD88-`Eb$kYPPuf8sU~mtH`tp>+xQAE@B)38->d!t-B)(@)q%YI4^E)PGz-z z-6Z~C!Dbl;y9$QncFjR(``IJ-VmE0M9~)~IxzQkKQL56QP^nB#$D3Ji07C{I6{?rT z<1;c`ES)J&C+=Yo_N*B;}2`Qcx0 zv}&EcB1A_wIoF`b{j#;LIjiRI7~Z z{PnTA23Db!?T37}EHW~(>CNG0YJ83K7#X0so)zk~N=p~SGEyBh*eT6rkE)N(bV;RD zEwa4>28t5ZsII9gPo%siF5U|)TUfo$8wN&R;O;yLKd!FM;ek1h(&|SxKl52CO-tAH zNm#w-Jr|XBJw=4~2W1*nf=0}S`?;{agM$(4^tVi4m+Xs-)qRx(rYwLE0VQP$o8^Y} z4H%zK)+eBEBX=631bC&<0ik2!U8@QV%67EB$!xMpl7fpXHPgM84~FP$jeRz`s@I^Gr}9Z_E|h7bFbGvI(7Di#2g-WF#gwE-nK35mY4!-zZMe-@PH+ z?#_9pRT!mLHufCS^YI?_=Jp;5N`H6f=%Avl-rucn<2_i4iPLcpY~p2K)%`R9U8;9q z_=0H5bR@{(cHtZrwoNz=e6Cq<9VZFsK~GEogXP9gK|z6niHb{yXLSDl7dlnC`c0`f zqot37qvNn58Y+%jdV0q2`h>JrgQzp!;C>G@a5B|R*q_L5&L#%_u07~zFES^7z#KFC zX=|qPhPnAlv#%UN7FXPbVF1Us5IsJL_BpkZDHLRsPsN87ssyU!WWpMSLY>RXyP?{y zqcIzAIYB|}B{Qov$*DNdF6Kmvz@d-f-(q^1)u@N^0l`6malyeJzBa4v+sVd=!CH3P z_|(fNcGT+~kH1VFD3x-B7)yV)5OwexlO*go&{{3E$0e4l86d-kET+#c+iO?a9W9Bs z+TU}nw|gZaFQ*}AW)FmZ&oP$9o+&m7ibhziuKhvZ!JDbSL@1Q=J$*`&IG8$Va5qB3 z#dM^W)p38tsnz|Q>|1aEG`6~)4W7#qM#Y;2iq%SM+{IdljiWViP=mRO!C|`0T%Cpp1TMqO z;>Ppv?{6|MkLLoicW0K!K`=CBn2#TZaaRKG?kP@h%RXBaRvVpZtGD3XFzflnM;MI0 z6hHGB=8J!(XdB*&4cr(>->kGc&_C9o<=UjIZH3XAjol({l)4$XU$^M3Pz1D=Yqx#% z>}7$bW`uzOOdLX2Rg4};W; zWe}20dbnYP-s-}H5XNAhiH`f&-UqWRTyCV5##L$37)$W#!SHn)U?hY@Ru@ zDD$9kWFjO%92oj)Kn~AlfzhAW<0H2w9z&4s_DQwD-pv3*1|Ek~ri)fvX0aL0&(Dv7 zkue3cG3kh2+4b#Yx&m~5yVE*CmwqTTqv7nyN?_RU(~vO=fm>;24YGpfCP%8fc! z?4}gM+tsPfWKC*xjIa;QhDbJ>RnjM<_RHzWEhM!Fmgu1ZV=R0s((^pP0d`*|!?Wbd zBxq@>b&dPCF0WUF+5YR@;yoRNfn6 zHt-%}lX0mYnYl9$1Tfqv3?~m7LOQ7UG9LKiTz?}R;!+lSz@0FHiV`eB!h9hw*xK zsPHa&ACP=<$FZdGy1RCloq~7U@$>_~EMcX%dknYtO6qpleWtT| zrE>3!Be#4tU(YyH2q)jIC?{U*I;qACTWzmvpK!UILpwh_iFmfWd5zZ~9PeMG4FFrM zpWR5;+|F;P@0Vdw6%urV0md@jw$?ZK3WQP*T#aTj+cd|;W8jnq_H)rj{-rF@j?#S z?5Ez}9hBvn4R`Zm?t}o;#W3GjUdg;Lwi&LsngYombfn*-FV+yo{{$T{t@V^8lX=}3 z1ua>GyDLy$FWfhE|Y|zL#KaUs99GIsMRO27gjdqvMt8W=SosFe{&^WmoA08pf z@^UZG)GZVaFc*5?SLkN0cr15lSDRu+WZk(11+gdLgTJ}(K81HjTNd!V!ZXor8tX0` z%or4M$JfXqyd3P9^<{&5S-g=Or#J;QpBVujCJ>++%iD7o)qj2_q~wy?81J_8QK+E$}8? zZ*y0DivAWo?8UuiC0C?@Dj+YB!Qx$SlE|uh{&YZ66)D{a)lb6U!q;gH2#7iMum1w* zM&U90h+;OKPEWa8n-!F@BwhLy$Q~-6dw2v{$okksO6G=oI007Z{f1ZZ^ltLvIKw?x z9#WDICC*BHio<7&hDTx+xK*>!X$9l{Sy5B&ekMxFY7FMMw#=ttj3~i7ie$xnetO9a z`voySoNTBUH#YqI<{BXL>fRVDT!|NTW$8gLt1uT(;JE3-oRCQW5whWF

    Ubd)poe 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 { await q({ query, variables: { productId: product2.id } }); await q({ query, variables: { productId: product1.id } }); const result1 = await context.sudo().lists.CartItem.findMany({ - where: { product: { id: product1.id } }, + where: { product: { id: { equals: product1.id } } }, query: 'quantity', }); expect(result1).toHaveLength(1); expect(result1[0].quantity).toEqual(3); const result2 = await context.sudo().lists.CartItem.findMany({ - where: { product: { id: product2.id } }, + where: { product: { id: { equals: product2.id } } }, query: 'quantity', }); expect(result2).toHaveLength(1); diff --git a/examples-staging/embedded-nextjs/CHANGELOG.md b/examples-staging/embedded-nextjs/CHANGELOG.md index cb97e8a55a9..9e03eb1293c 100644 --- a/examples-staging/embedded-nextjs/CHANGELOG.md +++ b/examples-staging/embedded-nextjs/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-next-lite +## 3.0.6 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 3.0.5 ### Patch Changes diff --git a/examples-staging/embedded-nextjs/package.json b/examples-staging/embedded-nextjs/package.json index e09673d4696..54d6edeac8c 100644 --- a/examples-staging/embedded-nextjs/package.json +++ b/examples-staging/embedded-nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-embedded-nextjs", - "version": "3.0.5", + "version": "3.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", "dotenv": "^10.0.0", "next": "^10.2.3", "react": "^17.0.2", diff --git a/examples-staging/embedded-nextjs/schema.graphql b/examples-staging/embedded-nextjs/schema.graphql index 4aeb0f138f9..0c723ddb1de 100644 --- a/examples-staging/embedded-nextjs/schema.graphql +++ b/examples-staging/embedded-nextjs/schema.graphql @@ -8,32 +8,50 @@ type Post { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] - slug: String - slug_not: String - slug_contains: String - slug_not_contains: String - slug_in: [String] - slug_not_in: [String] - content: String - content_not: String - content_contains: String - content_not_contains: String - content_in: [String] - content_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + slug: StringNullableFilter + content: StringNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } input PostWhereUniqueInput { @@ -90,7 +108,7 @@ type Query { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post diff --git a/examples-staging/graphql-api-endpoint/CHANGELOG.md b/examples-staging/graphql-api-endpoint/CHANGELOG.md index c12e0035a69..3ba38d49da6 100644 --- a/examples-staging/graphql-api-endpoint/CHANGELOG.md +++ b/examples-staging/graphql-api-endpoint/CHANGELOG.md @@ -1,5 +1,17 @@ # keystone-next-app +## 1.0.6 + +### Patch Changes + +- [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`e985aa010`](https://github.com/keystonejs/keystone/commit/e985aa0104d30a779f21ec05d80e6b98ece87dfb), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`69f47bfed`](https://github.com/keystonejs/keystone/commit/69f47bfed1eaa1269cfdc42071268a914bd4aa17), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/fields-document@8.0.0 + - @keystone-next/auth@31.0.0 + ## 1.0.5 ### Patch Changes diff --git a/examples-staging/graphql-api-endpoint/package.json b/examples-staging/graphql-api-endpoint/package.json index a8b38a078d8..11958b4f72c 100644 --- a/examples-staging/graphql-api-endpoint/package.json +++ b/examples-staging/graphql-api-endpoint/package.json @@ -1,6 +1,6 @@ { "name": "keystone-next-app", - "version": "1.0.5", + "version": "1.0.6", "private": true, "scripts": { "dev": "keystone-next dev", @@ -11,11 +11,11 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.14.8", - "@keystone-next/auth": "^30.0.0", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/fields-document": "^7.0.3", - "@keystone-next/keystone": "^23.0.0", + "@babel/runtime": "^7.15.3", + "@keystone-next/auth": "^31.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/fields-document": "^8.0.0", + "@keystone-next/keystone": "^24.0.0", "apollo-server-micro": "^2.25.2" }, "repository": "https://github.com/keystonejs/keystone/tree/master/examples-staging/graphql-api-endpoint" diff --git a/examples-staging/graphql-api-endpoint/schema.graphql b/examples-staging/graphql-api-endpoint/schema.graphql index 13fde63066a..1203d46c607 100644 --- a/examples-staging/graphql-api-endpoint/schema.graphql +++ b/examples-staging/graphql-api-endpoint/schema.graphql @@ -1,3 +1,62 @@ +input CreateInitialUserInput { + name: String + email: String + password: String +} + +type Mutation { + createInitialUser( + data: CreateInitialUserInput! + ): UserAuthenticationWithPasswordSuccess! + authenticateUserWithPassword( + email: String! + password: String! + ): UserAuthenticationWithPasswordResult! + createUser(data: UserCreateInput!): User + createUsers(data: [UserCreateInput!]!): [User] + updateUser(where: UserWhereUniqueInput!, data: UserUpdateInput!): User + updateUsers(data: [UserUpdateArgs!]!): [User] + deleteUser(where: UserWhereUniqueInput!): User + deleteUsers(where: [UserWhereUniqueInput!]!): [User] + createPost(data: PostCreateInput!): Post + createPosts(data: [PostCreateInput!]!): [Post] + updatePost(where: PostWhereUniqueInput!, data: PostUpdateInput!): Post + updatePosts(data: [PostUpdateArgs!]!): [Post] + deletePost(where: PostWhereUniqueInput!): Post + deletePosts(where: [PostWhereUniqueInput!]!): [Post] + createTag(data: TagCreateInput!): Tag + createTags(data: [TagCreateInput!]!): [Tag] + updateTag(where: TagWhereUniqueInput!, data: TagUpdateInput!): Tag + updateTags(data: [TagUpdateArgs!]!): [Tag] + deleteTag(where: TagWhereUniqueInput!): Tag + deleteTags(where: [TagWhereUniqueInput!]!): [Tag] + endSession: Boolean! +} + +union AuthenticatedItem = User + +union UserAuthenticationWithPasswordResult = + UserAuthenticationWithPasswordSuccess + | UserAuthenticationWithPasswordFailure + +type UserAuthenticationWithPasswordSuccess { + sessionToken: String! + item: User! +} + +type UserAuthenticationWithPasswordFailure { + code: PasswordAuthErrorCode! + message: String! +} + +enum PasswordAuthErrorCode { + FAILURE + IDENTITY_NOT_FOUND + SECRET_NOT_SET + MULTIPLE_IDENTITY_MATCHES + SECRET_MISMATCH +} + type User { id: ID! name: String @@ -6,7 +65,7 @@ type User { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -19,54 +78,67 @@ type PasswordState { input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_starts_with: String - name_not_starts_with: String - name_ends_with: String - name_not_ends_with: String - name_i: String - name_not_i: String - name_contains_i: String - name_not_contains_i: String - name_starts_with_i: String - name_not_starts_with_i: String - name_ends_with_i: String - name_not_ends_with_i: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_starts_with: String - email_not_starts_with: String - email_ends_with: String - email_not_ends_with: String - email_i: String - email_not_i: String - email_contains_i: String - email_not_contains_i: String - email_starts_with_i: String - email_not_starts_with_i: String - email_ends_with_i: String - email_not_ends_with_i: String - email_in: [String] - email_not_in: [String] - password_is_set: Boolean - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [UserWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + password: PasswordFilter + posts: PostManyRelationFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + mode: QueryMode + not: NestedStringNullableFilter +} + +enum QueryMode { + default + insensitive +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input PasswordFilter { + isSet: Boolean! +} + +input PostManyRelationFilter { + every: PostWhereInput + some: PostWhereInput + none: PostWhereInput } input UserWhereUniqueInput { @@ -126,7 +198,7 @@ type Post { tags( where: TagWhereInput! = {} orderBy: [TagOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Tag!] tagsCount(where: TagWhereInput! = {}): Int @@ -139,49 +211,30 @@ type Post_content_DocumentField { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_starts_with: String - title_not_starts_with: String - title_ends_with: String - title_not_ends_with: String - title_i: String - title_not_i: String - title_contains_i: String - title_not_contains_i: String - title_starts_with_i: String - title_not_starts_with_i: String - title_ends_with_i: String - title_not_ends_with_i: String - title_in: [String] - title_not_in: [String] - status: String - status_not: String - status_in: [String] - status_not_in: [String] - publishDate: String - publishDate_not: String - publishDate_lt: String - publishDate_lte: String - publishDate_gt: String - publishDate_gte: String - publishDate_in: [String] - publishDate_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + status: StringNullableFilter + publishDate: DateTimeNullableFilter author: UserWhereInput - author_is_null: Boolean - tags_every: TagWhereInput - tags_some: TagWhereInput - tags_none: TagWhereInput + tags: TagManyRelationFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter +} + +input TagManyRelationFilter { + every: TagWhereInput + some: TagWhereInput + none: TagWhereInput } input PostWhereUniqueInput { @@ -247,7 +300,7 @@ type Tag { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -256,35 +309,10 @@ type Tag { input TagWhereInput { AND: [TagWhereInput!] OR: [TagWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_starts_with: String - name_not_starts_with: String - name_ends_with: String - name_not_ends_with: String - name_i: String - name_not_i: String - name_contains_i: String - name_not_contains_i: String - name_starts_with_i: String - name_not_starts_with_i: String - name_ends_with_i: String - name_not_ends_with_i: String - name_in: [String] - name_not_in: [String] - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [TagWhereInput!] + id: IDFilter + name: StringNullableFilter + posts: PostManyRelationFilter } input TagWhereUniqueInput { @@ -319,70 +347,12 @@ scalar JSON url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" ) -type Mutation { - createUser(data: UserCreateInput!): User - createUsers(data: [UserCreateInput!]!): [User] - updateUser(where: UserWhereUniqueInput!, data: UserUpdateInput!): User - updateUsers(data: [UserUpdateArgs!]!): [User] - deleteUser(where: UserWhereUniqueInput!): User - deleteUsers(where: [UserWhereUniqueInput!]!): [User] - createPost(data: PostCreateInput!): Post - createPosts(data: [PostCreateInput!]!): [Post] - updatePost(where: PostWhereUniqueInput!, data: PostUpdateInput!): Post - updatePosts(data: [PostUpdateArgs!]!): [Post] - deletePost(where: PostWhereUniqueInput!): Post - deletePosts(where: [PostWhereUniqueInput!]!): [Post] - createTag(data: TagCreateInput!): Tag - createTags(data: [TagCreateInput!]!): [Tag] - updateTag(where: TagWhereUniqueInput!, data: TagUpdateInput!): Tag - updateTags(data: [TagUpdateArgs!]!): [Tag] - deleteTag(where: TagWhereUniqueInput!): Tag - deleteTags(where: [TagWhereUniqueInput!]!): [Tag] - authenticateUserWithPassword( - email: String! - password: String! - ): UserAuthenticationWithPasswordResult! - createInitialUser( - data: CreateInitialUserInput! - ): UserAuthenticationWithPasswordSuccess! - endSession: Boolean! -} - -union AuthenticatedItem = User - -union UserAuthenticationWithPasswordResult = - UserAuthenticationWithPasswordSuccess - | UserAuthenticationWithPasswordFailure - -type UserAuthenticationWithPasswordSuccess { - sessionToken: String! - item: User! -} - -type UserAuthenticationWithPasswordFailure { - code: PasswordAuthErrorCode! - message: String! -} - -enum PasswordAuthErrorCode { - FAILURE - IDENTITY_NOT_FOUND - SECRET_NOT_SET - MULTIPLE_IDENTITY_MATCHES - SECRET_MISMATCH -} - -input CreateInitialUserInput { - name: String - email: String - password: String -} - type Query { + authenticatedItem: AuthenticatedItem users( where: UserWhereInput! = {} orderBy: [UserOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [User!] user(where: UserWhereUniqueInput!): User @@ -390,7 +360,7 @@ type Query { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post @@ -398,12 +368,11 @@ type Query { tags( where: TagWhereInput! = {} orderBy: [TagOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Tag!] tag(where: TagWhereUniqueInput!): Tag tagsCount(where: TagWhereInput! = {}): Int - authenticatedItem: AuthenticatedItem keystone: KeystoneMeta! } @@ -478,11 +447,6 @@ enum KeystoneAdminUIFieldMetaItemViewFieldMode { hidden } -enum QueryMode { - default - insensitive -} - type KeystoneAdminUISort { field: String! direction: KeystoneAdminUISortDirection! diff --git a/examples-staging/playground/CHANGELOG.md b/examples-staging/playground/CHANGELOG.md index 2fc651dc077..fe7a35f17b9 100644 --- a/examples-staging/playground/CHANGELOG.md +++ b/examples-staging/playground/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-playground +## 1.0.5 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 1.0.4 ### Patch Changes diff --git a/examples-staging/playground/package.json b/examples-staging/playground/package.json index b81a675af63..b9720b7c057 100644 --- a/examples-staging/playground/package.json +++ b/examples-staging/playground/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-playground", - "version": "1.0.4", + "version": "1.0.5", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples-staging/playground/schema.graphql b/examples-staging/playground/schema.graphql index f7dd94aea96..67148d43a55 100644 --- a/examples-staging/playground/schema.graphql +++ b/examples-staging/playground/schema.graphql @@ -6,20 +6,48 @@ type Note { input NoteWhereInput { AND: [NoteWhereInput!] OR: [NoteWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] + NOT: [NoteWhereInput!] + id: IDFilter + label: StringNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } input NoteWhereUniqueInput { @@ -70,7 +98,7 @@ type Query { notes( where: NoteWhereInput! = {} orderBy: [NoteOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Note!] note(where: NoteWhereUniqueInput!): Note diff --git a/examples-staging/roles/CHANGELOG.md b/examples-staging/roles/CHANGELOG.md index 61de99f174e..25431826da1 100644 --- a/examples-staging/roles/CHANGELOG.md +++ b/examples-staging/roles/CHANGELOG.md @@ -1,5 +1,17 @@ # @keystone-next/example-roles +## 4.0.6 + +### Patch Changes + +- [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + - @keystone-next/auth@31.0.0 + ## 4.0.5 ### Patch Changes diff --git a/examples-staging/roles/access.ts b/examples-staging/roles/access.ts index 25eb86a5195..4f31e1c101a 100644 --- a/examples-staging/roles/access.ts +++ b/examples-staging/roles/access.ts @@ -32,14 +32,14 @@ export const rules = { // Can see all todos that are: assigned to them, or not private return { OR: [ - { assignedTo: { id: session.itemId } }, - { assignedTo_is_null: true, isPrivate: true }, - { isPrivate_not: true }, + { assignedTo: { id: { equals: session.itemId } } }, + { assignedTo: null, isPrivate: { equals: true } }, + { NOT: { isPrivate: { equals: true } } }, ], }; } else { // Can only see their own todos - return { assignedTo: { id: session.itemId } }; + return { assignedTo: { id: { equals: session.itemId } } }; } }, canManageTodos: ({ session }: ListAccessArgs) => { @@ -51,7 +51,7 @@ export const rules = { return true; } else { // Can only manage their own todos - return { assignedTo: { id: session.itemId } }; + return { assignedTo: { id: { equals: session.itemId } } }; } }, canReadPeople: ({ session }: ListAccessArgs) => { @@ -63,7 +63,7 @@ export const rules = { return true; } else { // Can only see yourself - return { id: session.itemId }; + return { id: { equals: session.itemId } }; } }, canUpdatePeople: ({ session }: ListAccessArgs) => { @@ -75,7 +75,7 @@ export const rules = { return true; } else { // Can update yourself - return { id: session.itemId }; + return { id: { equals: session.itemId } }; } }, }; diff --git a/examples-staging/roles/package.json b/examples-staging/roles/package.json index 07f1b9f6494..7734e122ecf 100644 --- a/examples-staging/roles/package.json +++ b/examples-staging/roles/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-roles", - "version": "4.0.5", + "version": "4.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,10 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/auth": "^30.0.0", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", + "@keystone-next/auth": "^31.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "next": "^10.2.3", "react": "^17.0.2", "react-dom": "^17.0.2" diff --git a/examples-staging/roles/schema.graphql b/examples-staging/roles/schema.graphql index be44e3407d0..ba8201c3db0 100644 --- a/examples-staging/roles/schema.graphql +++ b/examples-staging/roles/schema.graphql @@ -1,3 +1,62 @@ +input CreateInitialPersonInput { + name: String + email: String + password: String +} + +type Mutation { + createInitialPerson( + data: CreateInitialPersonInput! + ): PersonAuthenticationWithPasswordSuccess! + authenticatePersonWithPassword( + email: String! + password: String! + ): PersonAuthenticationWithPasswordResult! + createTodo(data: TodoCreateInput!): Todo + createTodos(data: [TodoCreateInput!]!): [Todo] + updateTodo(where: TodoWhereUniqueInput!, data: TodoUpdateInput!): Todo + updateTodos(data: [TodoUpdateArgs!]!): [Todo] + deleteTodo(where: TodoWhereUniqueInput!): Todo + deleteTodos(where: [TodoWhereUniqueInput!]!): [Todo] + createPerson(data: PersonCreateInput!): Person + createPeople(data: [PersonCreateInput!]!): [Person] + updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person + updatePeople(data: [PersonUpdateArgs!]!): [Person] + deletePerson(where: PersonWhereUniqueInput!): Person + deletePeople(where: [PersonWhereUniqueInput!]!): [Person] + createRole(data: RoleCreateInput!): Role + createRoles(data: [RoleCreateInput!]!): [Role] + updateRole(where: RoleWhereUniqueInput!, data: RoleUpdateInput!): Role + updateRoles(data: [RoleUpdateArgs!]!): [Role] + deleteRole(where: RoleWhereUniqueInput!): Role + deleteRoles(where: [RoleWhereUniqueInput!]!): [Role] + endSession: Boolean! +} + +union AuthenticatedItem = Person + +union PersonAuthenticationWithPasswordResult = + PersonAuthenticationWithPasswordSuccess + | PersonAuthenticationWithPasswordFailure + +type PersonAuthenticationWithPasswordSuccess { + sessionToken: String! + item: Person! +} + +type PersonAuthenticationWithPasswordFailure { + code: PasswordAuthErrorCode! + message: String! +} + +enum PasswordAuthErrorCode { + FAILURE + IDENTITY_NOT_FOUND + SECRET_NOT_SET + MULTIPLE_IDENTITY_MATCHES + SECRET_MISMATCH +} + type Todo { id: ID! label: String @@ -9,26 +68,56 @@ type Todo { input TodoWhereInput { AND: [TodoWhereInput!] OR: [TodoWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - isComplete: Boolean - isComplete_not: Boolean - isPrivate: Boolean - isPrivate_not: Boolean + NOT: [TodoWhereInput!] + id: IDFilter + label: StringNullableFilter + isComplete: BooleanNullableFilter + isPrivate: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter } input TodoWhereUniqueInput { @@ -86,7 +175,7 @@ type Person { tasks( where: TodoWhereInput! = {} orderBy: [TodoOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Todo!] tasksCount(where: TodoWhereInput! = {}): Int @@ -99,32 +188,23 @@ type PasswordState { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - password_is_set: Boolean + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + password: PasswordFilter role: RoleWhereInput - role_is_null: Boolean - tasks_every: TodoWhereInput - tasks_some: TodoWhereInput - tasks_none: TodoWhereInput + tasks: TodoManyRelationFilter +} + +input PasswordFilter { + isSet: Boolean! +} + +input TodoManyRelationFilter { + every: TodoWhereInput + some: TodoWhereInput + none: TodoWhereInput } input PersonWhereUniqueInput { @@ -194,7 +274,7 @@ type Role { assignedTo( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] assignedToCount(where: PersonWhereInput! = {}): Int @@ -203,35 +283,22 @@ type Role { input RoleWhereInput { AND: [RoleWhereInput!] OR: [RoleWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - canCreateTodos: Boolean - canCreateTodos_not: Boolean - canManageAllTodos: Boolean - canManageAllTodos_not: Boolean - canSeeOtherPeople: Boolean - canSeeOtherPeople_not: Boolean - canEditOtherPeople: Boolean - canEditOtherPeople_not: Boolean - canManagePeople: Boolean - canManagePeople_not: Boolean - canManageRoles: Boolean - canManageRoles_not: Boolean - assignedTo_every: PersonWhereInput - assignedTo_some: PersonWhereInput - assignedTo_none: PersonWhereInput + NOT: [RoleWhereInput!] + id: IDFilter + name: StringNullableFilter + canCreateTodos: BooleanNullableFilter + canManageAllTodos: BooleanNullableFilter + canSeeOtherPeople: BooleanNullableFilter + canEditOtherPeople: BooleanNullableFilter + canManagePeople: BooleanNullableFilter + canManageRoles: BooleanNullableFilter + assignedTo: PersonManyRelationFilter +} + +input PersonManyRelationFilter { + every: PersonWhereInput + some: PersonWhereInput + none: PersonWhereInput } input RoleWhereUniqueInput { @@ -296,70 +363,12 @@ scalar JSON url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" ) -type Mutation { - createTodo(data: TodoCreateInput!): Todo - createTodos(data: [TodoCreateInput!]!): [Todo] - updateTodo(where: TodoWhereUniqueInput!, data: TodoUpdateInput!): Todo - updateTodos(data: [TodoUpdateArgs!]!): [Todo] - deleteTodo(where: TodoWhereUniqueInput!): Todo - deleteTodos(where: [TodoWhereUniqueInput!]!): [Todo] - createPerson(data: PersonCreateInput!): Person - createPeople(data: [PersonCreateInput!]!): [Person] - updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person - updatePeople(data: [PersonUpdateArgs!]!): [Person] - deletePerson(where: PersonWhereUniqueInput!): Person - deletePeople(where: [PersonWhereUniqueInput!]!): [Person] - createRole(data: RoleCreateInput!): Role - createRoles(data: [RoleCreateInput!]!): [Role] - updateRole(where: RoleWhereUniqueInput!, data: RoleUpdateInput!): Role - updateRoles(data: [RoleUpdateArgs!]!): [Role] - deleteRole(where: RoleWhereUniqueInput!): Role - deleteRoles(where: [RoleWhereUniqueInput!]!): [Role] - authenticatePersonWithPassword( - email: String! - password: String! - ): PersonAuthenticationWithPasswordResult! - createInitialPerson( - data: CreateInitialPersonInput! - ): PersonAuthenticationWithPasswordSuccess! - endSession: Boolean! -} - -union AuthenticatedItem = Person - -union PersonAuthenticationWithPasswordResult = - PersonAuthenticationWithPasswordSuccess - | PersonAuthenticationWithPasswordFailure - -type PersonAuthenticationWithPasswordSuccess { - sessionToken: String! - item: Person! -} - -type PersonAuthenticationWithPasswordFailure { - code: PasswordAuthErrorCode! - message: String! -} - -enum PasswordAuthErrorCode { - FAILURE - IDENTITY_NOT_FOUND - SECRET_NOT_SET - MULTIPLE_IDENTITY_MATCHES - SECRET_MISMATCH -} - -input CreateInitialPersonInput { - name: String - email: String - password: String -} - type Query { + authenticatedItem: AuthenticatedItem todos( where: TodoWhereInput! = {} orderBy: [TodoOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Todo!] todo(where: TodoWhereUniqueInput!): Todo @@ -367,7 +376,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person @@ -375,12 +384,11 @@ type Query { roles( where: RoleWhereInput! = {} orderBy: [RoleOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Role!] role(where: RoleWhereUniqueInput!): Role rolesCount(where: RoleWhereInput! = {}): Int - authenticatedItem: AuthenticatedItem keystone: KeystoneMeta! } diff --git a/examples-staging/sandbox/CHANGELOG.md b/examples-staging/sandbox/CHANGELOG.md index 6c26440d40d..e4c02593c4f 100644 --- a/examples-staging/sandbox/CHANGELOG.md +++ b/examples-staging/sandbox/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-sandbox +## 3.0.6 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/auth@31.0.0 + ## 3.0.5 ### Patch Changes diff --git a/examples-staging/sandbox/package.json b/examples-staging/sandbox/package.json index faa9b468701..23899c25be7 100644 --- a/examples-staging/sandbox/package.json +++ b/examples-staging/sandbox/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-sandbox", - "version": "3.0.5", + "version": "3.0.6", "private": true, "license": "MIT", "scripts": { @@ -8,9 +8,9 @@ "sandbox": "yarn && yarn dev" }, "dependencies": { - "@keystone-next/auth": "^30.0.0", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/auth": "^31.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/sandbox/schema.graphql b/examples-staging/sandbox/schema.graphql index 66117bc9d9a..265367bfa79 100644 --- a/examples-staging/sandbox/schema.graphql +++ b/examples-staging/sandbox/schema.graphql @@ -11,48 +11,69 @@ type Todo { input TodoWhereInput { AND: [TodoWhereInput!] OR: [TodoWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TodoWhereInput!] + id: IDFilter + label: StringNullableFilter + isComplete: BooleanNullableFilter assignedTo: UserWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] - createdAt: String - createdAt_not: String - createdAt_lt: String - createdAt_lte: String - createdAt_gt: String - createdAt_gte: String - createdAt_in: [String] - createdAt_not_in: [String] - updatedAt: String - updatedAt_not: String - updatedAt_lt: String - updatedAt_lte: String - updatedAt_gt: String - updatedAt_gte: String - updatedAt_in: [String] - updatedAt_not_in: [String] + finishBy: DateTimeNullableFilter + createdAt: DateTimeNullableFilter + updatedAt: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TodoWhereUniqueInput { @@ -111,7 +132,7 @@ type User { tasks( where: TodoWhereInput! = {} orderBy: [TodoOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Todo!] tasksCount(where: TodoWhereInput! = {}): Int @@ -126,46 +147,24 @@ type PasswordState { input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - password_is_set: Boolean - tasks_every: TodoWhereInput - tasks_some: TodoWhereInput - tasks_none: TodoWhereInput - createdAt: String - createdAt_not: String - createdAt_lt: String - createdAt_lte: String - createdAt_gt: String - createdAt_gte: String - createdAt_in: [String] - createdAt_not_in: [String] - updatedAt: String - updatedAt_not: String - updatedAt_lt: String - updatedAt_lte: String - updatedAt_gt: String - updatedAt_gte: String - updatedAt_in: [String] - updatedAt_not_in: [String] + NOT: [UserWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + password: PasswordFilter + tasks: TodoManyRelationFilter + createdAt: DateTimeNullableFilter + updatedAt: DateTimeNullableFilter +} + +input PasswordFilter { + isSet: Boolean! +} + +input TodoManyRelationFilter { + every: TodoWhereInput + some: TodoWhereInput + none: TodoWhereInput } input UserWhereUniqueInput { @@ -238,7 +237,7 @@ type Query { todos( where: TodoWhereInput! = {} orderBy: [TodoOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Todo!] todo(where: TodoWhereUniqueInput!): Todo @@ -246,7 +245,7 @@ type Query { users( where: UserWhereInput! = {} orderBy: [UserOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [User!] user(where: UserWhereUniqueInput!): User diff --git a/examples/blog/CHANGELOG.md b/examples/blog/CHANGELOG.md index e6b48d54dff..d15f710f338 100644 --- a/examples/blog/CHANGELOG.md +++ b/examples/blog/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-blog +## 2.0.6 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 2.0.5 ### Patch Changes diff --git a/examples/blog/package.json b/examples/blog/package.json index 047521e8beb..d9bac9e7a8d 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-blog", - "version": "2.0.5", + "version": "2.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/blog/schema.graphql b/examples/blog/schema.graphql index 1cd125ef525..1dd72c9481f 100644 --- a/examples/blog/schema.graphql +++ b/examples/blog/schema.graphql @@ -15,40 +15,70 @@ enum PostStatusType { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] - status: PostStatusType - status_not: PostStatusType - status_in: [PostStatusType] - status_not_in: [PostStatusType] - content: String - content_not: String - content_contains: String - content_not_contains: String - content_in: [String] - content_not_in: [String] - publishDate: String - publishDate_not: String - publishDate_lt: String - publishDate_lte: String - publishDate_gt: String - publishDate_gte: String - publishDate_in: [String] - publishDate_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + status: PostStatusTypeNullableFilter + content: StringNullableFilter + publishDate: DateTimeNullableFilter author: AuthorWhereInput - author_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input PostStatusTypeNullableFilter { + equals: PostStatusType + in: [PostStatusType!] + notIn: [PostStatusType!] + not: PostStatusTypeNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input PostWhereUniqueInput { @@ -107,7 +137,7 @@ type Author { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -116,29 +146,17 @@ type Author { input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [AuthorWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + posts: PostManyRelationFilter +} + +input PostManyRelationFilter { + every: PostWhereInput + some: PostWhereInput + none: PostWhereInput } input AuthorWhereUniqueInput { @@ -208,7 +226,7 @@ type Query { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post @@ -216,7 +234,7 @@ type Query { authors( where: AuthorWhereInput! = {} orderBy: [AuthorOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Author!] author(where: AuthorWhereUniqueInput!): Author diff --git a/examples/custom-admin-ui-logo/CHANGELOG.md b/examples/custom-admin-ui-logo/CHANGELOG.md index fc29b50ebb5..000593008f5 100644 --- a/examples/custom-admin-ui-logo/CHANGELOG.md +++ b/examples/custom-admin-ui-logo/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-custom-admin-ui-logo +## 1.0.1 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + ## 1.0.0 ### Major Changes diff --git a/examples/custom-admin-ui-logo/package.json b/examples/custom-admin-ui-logo/package.json index 6450ae841c8..376a249bed9 100644 --- a/examples/custom-admin-ui-logo/package.json +++ b/examples/custom-admin-ui-logo/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-admin-ui-logo", - "version": "1.0.0", + "version": "1.0.1", "private": true, "license": "MIT", "scripts": { @@ -9,9 +9,9 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/core": "^3.1.0", "next": "^10.2.3", "react": "^17.0.2" diff --git a/examples/custom-admin-ui-logo/schema.graphql b/examples/custom-admin-ui-logo/schema.graphql index 49a0f225167..e194b7cb406 100644 --- a/examples/custom-admin-ui-logo/schema.graphql +++ b/examples/custom-admin-ui-logo/schema.graphql @@ -16,36 +16,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -103,7 +142,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -112,23 +151,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,7 +226,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -202,7 +234,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/custom-admin-ui-navigation/CHANGELOG.md b/examples/custom-admin-ui-navigation/CHANGELOG.md index 1aabc24b86e..a9d48b60e5a 100644 --- a/examples/custom-admin-ui-navigation/CHANGELOG.md +++ b/examples/custom-admin-ui-navigation/CHANGELOG.md @@ -1 +1,14 @@ # @keystone-next/example-custom-navigation-component + +## 5.0.0 + +### Major Changes + +- [#6185](https://github.com/keystonejs/keystone/pull/6185) [`bc00c0a17`](https://github.com/keystonejs/keystone/commit/bc00c0a17b41a9ef016ec41b59ac394013be916d) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Initial version of the custom-admin-ui-navigation example. + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 diff --git a/examples/custom-admin-ui-navigation/package.json b/examples/custom-admin-ui-navigation/package.json index bc9c7a10355..461c3c0d424 100644 --- a/examples/custom-admin-ui-navigation/package.json +++ b/examples/custom-admin-ui-navigation/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-admin-ui-navigation", - "version": "4.0.4", + "version": "5.0.0", "private": true, "license": "MIT", "scripts": { @@ -9,9 +9,9 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.1", - "@keystone-next/types": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "react": "^17.0.2" }, "devDependencies": { diff --git a/examples/custom-admin-ui-navigation/schema.graphql b/examples/custom-admin-ui-navigation/schema.graphql index 49a0f225167..e194b7cb406 100644 --- a/examples/custom-admin-ui-navigation/schema.graphql +++ b/examples/custom-admin-ui-navigation/schema.graphql @@ -16,36 +16,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -103,7 +142,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -112,23 +151,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,7 +226,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -202,7 +234,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/custom-admin-ui-pages/CHANGELOG.md b/examples/custom-admin-ui-pages/CHANGELOG.md index 88b4c31f841..68e1f42b5a0 100644 --- a/examples/custom-admin-ui-pages/CHANGELOG.md +++ b/examples/custom-admin-ui-pages/CHANGELOG.md @@ -1 +1,16 @@ # @keystone-next/example-custom-admin-ui-pages + +## 1.0.0 + +### Major Changes + +- [#6082](https://github.com/keystonejs/keystone/pull/6082) [`e0b9e8d38`](https://github.com/keystonejs/keystone/commit/e0b9e8d38b0d531bcc921f05435bd1985b47781a) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Initial version of the custom-admin-ui-pages example. + +### Patch Changes + +- [#6264](https://github.com/keystonejs/keystone/pull/6264) [`df10c42a2`](https://github.com/keystonejs/keystone/commit/df10c42a2c4fb4d48060b118de3111fd14cdc412) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Additional content added to example for making the custom-page look more like the Admin UI, as well as adding a route to the custom page to the Admin UI Navigation. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 diff --git a/examples/custom-admin-ui-pages/README.md b/examples/custom-admin-ui-pages/README.md index 37622aac6b1..59b084aba29 100644 --- a/examples/custom-admin-ui-pages/README.md +++ b/examples/custom-admin-ui-pages/README.md @@ -19,10 +19,44 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// 🚀 Congratulations, you're now up and running with Keystone! -## admin/pages +## /admin/pages -This project leverages the `/admin/pages` directory. As elaborated on in the [Custom Pages](https://keystonejs.com/docs/guides/custom-admin-ui-pages) guide, this directory is used to generate additional routes in the Admin UI, a behaviour inherited from `Next.js`. The default export of files in this directory are expected to be **React Components**. +This project leverages the `/admin/pages` directory. As elaborated on in the [Custom Pages](https://keystonejs.com/docs/guides/custom-admin-ui-pages) guide, this directory is used to generate additional pages in the Admin UI, a behaviour inherited from `Next.js`. The default export of files in this directory are expected to be **React Components**. **All other exports are ignored** -**NOTE** The Keystone monorepo leverages a babel config that means we use the old jsx transform (this doesn't have an impact on the code we ship to npm). -This is why there are `import React from 'react'` statements in our examples, this is NOT necessary outside of the Keystone repo (unless you have a babel config with the old jsx transform which is currently the default with @babel/preset-react) as you'll be using Next's babel config which uses the new jsx transform. +**NOTE**: The Keystone monorepo leverages a babel config that means we use the old jsx transform (this doesn't have an impact on the code we ship to npm). +This is why there are `import React from 'react'` statements in our examples, this is NOT necessary outside of the Keystone repo (unless you have a babel config with the old jsx transform which is currently the default with `@babel/preset-react`) as you'll be using Next's babel config which uses the new jsx transform. + +## Custom Navigation + +In order to ensure that the new page is visible and navigable within the Admin UI, this example also adds a custom Navigation component with the +route to the custom page included. For much more detail on adding custom navigation, please see the Custom Admin UI Navigation [guide](https://keystonejs.com/docs/guides/custom-admin-ui-navigation) and [example](../custom-admin-ui-navigation). + +## Layout components + +In order to help us build custom pages that _look_ and _feel_ like part of the Admin UI, Keystone exports the `PageContainer` component from +the `@keystone-next/keystone/admin-ui/components` package. + +### PageContainer + +PageContainer has the following types: + +```typescript +type PageContainerProps = { + header: ReactElement; + children: ReactNode; +}; +``` + +To match the header style applied to all Admin UI standard pages, we use the `Heading` component from `@keystone-ui/core` as an `h3` element. + +```tsx +import { PageContainer } from '@keystone-next/keystone/admin-ui/component'; +import { Heading } from '@keystone-ui/core'; + +export default () => { + return ( + Custom Page}>{/* ... */} + ); +}; +``` diff --git a/examples/custom-admin-ui-pages/admin/components/CustomNavigation.tsx b/examples/custom-admin-ui-pages/admin/components/CustomNavigation.tsx new file mode 100644 index 00000000000..4c30c4d376a --- /dev/null +++ b/examples/custom-admin-ui-pages/admin/components/CustomNavigation.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { + NavItem, + ListNavItems, + NavigationContainer, +} from '@keystone-next/keystone/admin-ui/components'; +import type { NavigationProps } from '@keystone-next/keystone/admin-ui/components'; + +export function CustomNavigation({ lists, authenticatedItem }: NavigationProps) { + return ( + + Dashboard + + Custom Page + + ); +} diff --git a/examples/custom-admin-ui-pages/admin/config.ts b/examples/custom-admin-ui-pages/admin/config.ts new file mode 100644 index 00000000000..12e80c22bb2 --- /dev/null +++ b/examples/custom-admin-ui-pages/admin/config.ts @@ -0,0 +1,5 @@ +import type { AdminConfig } from '@keystone-next/types'; +import { CustomNavigation } from './components/CustomNavigation'; +export const components: AdminConfig['components'] = { + Navigation: CustomNavigation, +}; diff --git a/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx b/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx index f109f136375..4e14dbb36cf 100644 --- a/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx +++ b/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx @@ -1,34 +1,27 @@ /** @jsx jsx */ -import { Fragment } from 'react'; -import { jsx } from '@keystone-ui/core'; +import { PageContainer } from '@keystone-next/keystone/admin-ui/components'; +import { jsx, Heading } from '@keystone-ui/core'; // Please note that while this capability is driven by Next.js's pages directory // We do not currently support any of the auxillary methods that Next.js provides i.e. `getStaticProps` // Presently the only export from the directory that is supported is the page component itself. export default function CustomPage() { return ( - -

    Custom Page}> +

    -

    - Hello this is a custom page -

    -

    - This is a custom page added to the Admin UI, leveraging @keystone-ui/core -

    -
    - + This is a custom Admin UI Page + +

    + It can be accessed via the route /custom-page +

    + ); } diff --git a/examples/custom-admin-ui-pages/package.json b/examples/custom-admin-ui-pages/package.json index 574a7a771e8..c89af45ea77 100644 --- a/examples/custom-admin-ui-pages/package.json +++ b/examples/custom-admin-ui-pages/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-admin-ui-pages", - "version": "0.0.1", + "version": "1.0.0", "private": true, "license": "MIT", "scripts": { @@ -9,11 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/core": "^3.1.0", - "next": "^10.2.3", "react": "^17.0.2" }, "devDependencies": { diff --git a/examples/custom-admin-ui-pages/schema.graphql b/examples/custom-admin-ui-pages/schema.graphql index 49a0f225167..e194b7cb406 100644 --- a/examples/custom-admin-ui-pages/schema.graphql +++ b/examples/custom-admin-ui-pages/schema.graphql @@ -16,36 +16,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -103,7 +142,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -112,23 +151,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,7 +226,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -202,7 +234,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/custom-field-view/CHANGELOG.md b/examples/custom-field-view/CHANGELOG.md index 23caa3ea685..372a08a14be 100644 --- a/examples/custom-field-view/CHANGELOG.md +++ b/examples/custom-field-view/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-custom-field-view +## 1.0.2 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + ## 1.0.1 ### Patch Changes diff --git a/examples/custom-field-view/package.json b/examples/custom-field-view/package.json index c2882d1aa7d..cdf9cf19396 100644 --- a/examples/custom-field-view/package.json +++ b/examples/custom-field-view/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-field-view", - "version": "1.0.1", + "version": "1.0.2", "private": true, "license": "MIT", "scripts": { @@ -10,9 +10,9 @@ }, "dependencies": { "@emotion/css": "^11.1.3", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.1.1", "@keystone-ui/fields": "^4.1.2", diff --git a/examples/custom-field-view/schema.graphql b/examples/custom-field-view/schema.graphql index 049042c59fb..8f3770570e0 100644 --- a/examples/custom-field-view/schema.graphql +++ b/examples/custom-field-view/schema.graphql @@ -17,36 +17,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -106,7 +145,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -115,23 +154,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -197,7 +229,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -205,7 +237,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/custom-field/CHANGELOG.md b/examples/custom-field/CHANGELOG.md index a5efaa3027f..5e7867dc6a5 100644 --- a/examples/custom-field/CHANGELOG.md +++ b/examples/custom-field/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-custom-field +## 0.0.3 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + ## 0.0.2 ### Patch Changes diff --git a/examples/custom-field/package.json b/examples/custom-field/package.json index 79513877337..b8e4b695650 100644 --- a/examples/custom-field/package.json +++ b/examples/custom-field/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-field", - "version": "0.0.2", + "version": "0.0.3", "private": true, "license": "MIT", "scripts": { @@ -9,9 +9,9 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/fields": "^4.1.2", "react": "^17.0.2" }, diff --git a/examples/custom-field/schema.graphql b/examples/custom-field/schema.graphql index bce900c79cd..9a94c244dfd 100644 --- a/examples/custom-field/schema.graphql +++ b/examples/custom-field/schema.graphql @@ -16,48 +16,70 @@ enum PostStatusType { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] - status: PostStatusType - status_not: PostStatusType - status_in: [PostStatusType] - status_not_in: [PostStatusType] - content: String - content_not: String - content_contains: String - content_not_contains: String - content_in: [String] - content_not_in: [String] - rating: Int - rating_not: Int - rating_lt: Int - rating_lte: Int - rating_gt: Int - rating_gte: Int - rating_in: [Int] - rating_not_in: [Int] - publishDate: String - publishDate_not: String - publishDate_lt: String - publishDate_lte: String - publishDate_gt: String - publishDate_gte: String - publishDate_in: [String] - publishDate_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + status: PostStatusTypeNullableFilter + content: StringNullableFilter + publishDate: DateTimeNullableFilter author: AuthorWhereInput - author_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input PostStatusTypeNullableFilter { + equals: PostStatusType + in: [PostStatusType!] + notIn: [PostStatusType!] + not: PostStatusTypeNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input PostWhereUniqueInput { @@ -119,7 +141,7 @@ type Author { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -128,29 +150,17 @@ type Author { input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [AuthorWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + posts: PostManyRelationFilter +} + +input PostManyRelationFilter { + every: PostWhereInput + some: PostWhereInput + none: PostWhereInput } input AuthorWhereUniqueInput { @@ -220,7 +230,7 @@ type Query { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post @@ -228,7 +238,7 @@ type Query { authors( where: AuthorWhereInput! = {} orderBy: [AuthorOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Author!] author(where: AuthorWhereUniqueInput!): Author diff --git a/examples/default-values/CHANGELOG.md b/examples/default-values/CHANGELOG.md index 28487e9dc40..40fe398fb9a 100644 --- a/examples/default-values/CHANGELOG.md +++ b/examples/default-values/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-default-values +## 1.0.6 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 1.0.5 ### Patch Changes diff --git a/examples/default-values/package.json b/examples/default-values/package.json index 608ca218f02..af3ba2e7b19 100644 --- a/examples/default-values/package.json +++ b/examples/default-values/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-default-values", - "version": "1.0.5", + "version": "1.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/default-values/schema.graphql b/examples/default-values/schema.graphql index 49a0f225167..e194b7cb406 100644 --- a/examples/default-values/schema.graphql +++ b/examples/default-values/schema.graphql @@ -16,36 +16,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -103,7 +142,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -112,23 +151,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,7 +226,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -202,7 +234,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/default-values/schema.ts b/examples/default-values/schema.ts index f3f71a39b9e..945e8f259f5 100644 --- a/examples/default-values/schema.ts +++ b/examples/default-values/schema.ts @@ -30,7 +30,7 @@ export const lists = createSchema({ // Dynamic default: Find an anonymous user and assign the task to them defaultValue: async ({ context }) => { const anonymous = await context.lists.Person.findMany({ - where: { name: 'Anonymous' }, + where: { name: { equals: 'Anonymous' } }, }); if (anonymous.length > 0) { return { connect: { id: anonymous[0].id } }; diff --git a/examples/document-field/CHANGELOG.md b/examples/document-field/CHANGELOG.md index 52ab3591275..894c979f97a 100644 --- a/examples/document-field/CHANGELOG.md +++ b/examples/document-field/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-document-field +## 1.1.2 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`e985aa010`](https://github.com/keystonejs/keystone/commit/e985aa0104d30a779f21ec05d80e6b98ece87dfb), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`69f47bfed`](https://github.com/keystonejs/keystone/commit/69f47bfed1eaa1269cfdc42071268a914bd4aa17), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/fields-document@8.0.0 + ## 1.1.1 ### Patch Changes diff --git a/examples/document-field/package.json b/examples/document-field/package.json index e9684469656..03ffa30eeb0 100644 --- a/examples/document-field/package.json +++ b/examples/document-field/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-document-field", - "version": "1.1.1", + "version": "1.1.2", "private": true, "license": "MIT", "scripts": { @@ -11,9 +11,9 @@ }, "dependencies": { "@keystone-next/document-renderer": "^4.0.0", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/fields-document": "^7.0.3", - "@keystone-next/keystone": "^23.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/fields-document": "^8.0.0", + "@keystone-next/keystone": "^24.0.0", "@preconstruct/next": "^3.0.0", "next": "^10.2.3", "react": "^17.0.2" diff --git a/examples/document-field/schema.graphql b/examples/document-field/schema.graphql index 0c1e7ab5741..af2cccf7c54 100644 --- a/examples/document-field/schema.graphql +++ b/examples/document-field/schema.graphql @@ -20,40 +20,70 @@ type Post_content_DocumentField { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] - slug: String - slug_not: String - slug_contains: String - slug_not_contains: String - slug_in: [String] - slug_not_in: [String] - status: PostStatusType - status_not: PostStatusType - status_in: [PostStatusType] - status_not_in: [PostStatusType] - publishDate: String - publishDate_not: String - publishDate_lt: String - publishDate_lte: String - publishDate_gt: String - publishDate_gte: String - publishDate_in: [String] - publishDate_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + slug: StringNullableFilter + status: PostStatusTypeNullableFilter + publishDate: DateTimeNullableFilter author: AuthorWhereInput - author_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input PostStatusTypeNullableFilter { + equals: PostStatusType + in: [PostStatusType!] + notIn: [PostStatusType!] + not: PostStatusTypeNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input PostWhereUniqueInput { @@ -115,7 +145,7 @@ type Author { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -129,29 +159,17 @@ type Author_bio_DocumentField { input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [AuthorWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + posts: PostManyRelationFilter +} + +input PostManyRelationFilter { + every: PostWhereInput + some: PostWhereInput + none: PostWhereInput } input AuthorWhereUniqueInput { @@ -223,7 +241,7 @@ type Query { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post @@ -231,7 +249,7 @@ type Query { authors( where: AuthorWhereInput! = {} orderBy: [AuthorOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Author!] author(where: AuthorWhereUniqueInput!): Author diff --git a/examples/extend-graphql-schema/CHANGELOG.md b/examples/extend-graphql-schema/CHANGELOG.md index 24c56f59629..0982ae9ed25 100644 --- a/examples/extend-graphql-schema/CHANGELOG.md +++ b/examples/extend-graphql-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-extend-graphql-schema +## 1.0.6 + +### Patch Changes + +- [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 1.0.5 ### Patch Changes diff --git a/examples/extend-graphql-schema/README.md b/examples/extend-graphql-schema/README.md index 82ffce5897d..5047e37b0d4 100644 --- a/examples/extend-graphql-schema/README.md +++ b/examples/extend-graphql-schema/README.md @@ -105,7 +105,7 @@ We add a custom type to our schema using `type Statisics` in the `typeDefs`, and }); const { posts } = await context.lists.Author.findOne({ where: { id }, - query: 'posts(first: 1, orderBy: { publishDate: desc }) { id }', + query: 'posts(take: 1, orderBy: { publishDate: desc }) { id }', }); return { draft, published, latestPostId: posts ? posts[0].id : null }; }, diff --git a/examples/extend-graphql-schema/custom-schema.ts b/examples/extend-graphql-schema/custom-schema.ts index 42a9f9482f1..b29ddd7c49a 100644 --- a/examples/extend-graphql-schema/custom-schema.ts +++ b/examples/extend-graphql-schema/custom-schema.ts @@ -47,19 +47,19 @@ export const extendGraphqlSchema = graphQLSchemaExtension({ // If you accidentally use `context.lists.Post` here you can expect problems // when accessing the fields in your GraphQL client. return context.db.lists.Post.findMany({ - where: { author: { id }, publishDate_gt: cutoff }, + where: { author: { id: { equals: id } }, publishDate: { gt: cutoff } }, }); }, stats: async (root, { id }, context) => { const draft = await context.lists.Post.count({ - where: { author: { id }, status: 'draft' }, + where: { author: { id: { equals: id } }, status: { equals: 'draft' } }, }); const published = await context.lists.Post.count({ - where: { author: { id }, status: 'published' }, + where: { author: { id: { equals: id } }, status: { equals: 'published' } }, }); const { posts } = await context.lists.Author.findOne({ where: { id }, - query: 'posts(first: 1, orderBy: { publishDate: desc }) { id }', + query: 'posts(take: 1, orderBy: { publishDate: desc }) { id }', }); return { draft, published, latestPostId: posts ? posts[0].id : null }; }, diff --git a/examples/extend-graphql-schema/package.json b/examples/extend-graphql-schema/package.json index de95d078b43..e6dd1fab575 100644 --- a/examples/extend-graphql-schema/package.json +++ b/examples/extend-graphql-schema/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-extend-graphql-schema", - "version": "1.0.5", + "version": "1.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/extend-graphql-schema/schema.graphql b/examples/extend-graphql-schema/schema.graphql index 65fa2e55582..5268dc2c516 100644 --- a/examples/extend-graphql-schema/schema.graphql +++ b/examples/extend-graphql-schema/schema.graphql @@ -1,3 +1,31 @@ +type Mutation { + """ + Publish a post + """ + publishPost(id: ID!): Post + createPost(data: PostCreateInput!): Post + createPosts(data: [PostCreateInput!]!): [Post] + updatePost(where: PostWhereUniqueInput!, data: PostUpdateInput!): Post + updatePosts(data: [PostUpdateArgs!]!): [Post] + deletePost(where: PostWhereUniqueInput!): Post + deletePosts(where: [PostWhereUniqueInput!]!): [Post] + createAuthor(data: AuthorCreateInput!): Author + createAuthors(data: [AuthorCreateInput!]!): [Author] + updateAuthor(where: AuthorWhereUniqueInput!, data: AuthorUpdateInput!): Author + updateAuthors(data: [AuthorUpdateArgs!]!): [Author] + deleteAuthor(where: AuthorWhereUniqueInput!): Author + deleteAuthors(where: [AuthorWhereUniqueInput!]!): [Author] +} + +""" + A custom type to represent statistics for a user +""" +type Statistics { + draft: Int + published: Int + latest: Post +} + type Post { id: ID! title: String @@ -15,40 +43,70 @@ enum PostStatusType { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] - status: PostStatusType - status_not: PostStatusType - status_in: [PostStatusType] - status_not_in: [PostStatusType] - content: String - content_not: String - content_contains: String - content_not_contains: String - content_in: [String] - content_not_in: [String] - publishDate: String - publishDate_not: String - publishDate_lt: String - publishDate_lte: String - publishDate_gt: String - publishDate_gte: String - publishDate_in: [String] - publishDate_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + status: PostStatusTypeNullableFilter + content: StringNullableFilter + publishDate: DateTimeNullableFilter author: AuthorWhereInput - author_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input PostStatusTypeNullableFilter { + equals: PostStatusType + in: [PostStatusType!] + notIn: [PostStatusType!] + not: PostStatusTypeNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input PostWhereUniqueInput { @@ -107,7 +165,7 @@ type Author { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -116,29 +174,17 @@ type Author { input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [AuthorWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + posts: PostManyRelationFilter +} + +input PostManyRelationFilter { + every: PostWhereInput + some: PostWhereInput + none: PostWhereInput } input AuthorWhereUniqueInput { @@ -189,40 +235,20 @@ scalar JSON url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" ) -type Mutation { - createPost(data: PostCreateInput!): Post - createPosts(data: [PostCreateInput!]!): [Post] - updatePost(where: PostWhereUniqueInput!, data: PostUpdateInput!): Post - updatePosts(data: [PostUpdateArgs!]!): [Post] - deletePost(where: PostWhereUniqueInput!): Post - deletePosts(where: [PostWhereUniqueInput!]!): [Post] - createAuthor(data: AuthorCreateInput!): Author - createAuthors(data: [AuthorCreateInput!]!): [Author] - updateAuthor(where: AuthorWhereUniqueInput!, data: AuthorUpdateInput!): Author - updateAuthors(data: [AuthorUpdateArgs!]!): [Author] - deleteAuthor(where: AuthorWhereUniqueInput!): Author - deleteAuthors(where: [AuthorWhereUniqueInput!]!): [Author] - +type Query { """ - Publish a post + Return all posts for a user from the last days """ - publishPost(id: ID!): Post -} - -""" - A custom type to represent statistics for a user -""" -type Statistics { - draft: Int - published: Int - latest: Post -} + recentPosts(id: ID!, days: Int! = 7): [Post] -type Query { + """ + Compute statistics for a user + """ + stats(id: ID!): Statistics posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post @@ -230,21 +256,11 @@ type Query { authors( where: AuthorWhereInput! = {} orderBy: [AuthorOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Author!] author(where: AuthorWhereUniqueInput!): Author authorsCount(where: AuthorWhereInput! = {}): Int - - """ - Return all posts for a user from the last days - """ - recentPosts(id: ID!, days: Int! = 7): [Post] - - """ - Compute statistics for a user - """ - stats(id: ID!): Statistics keystone: KeystoneMeta! } diff --git a/examples/json/CHANGELOG.md b/examples/json/CHANGELOG.md index fd6d222ba2b..02b93900684 100644 --- a/examples/json/CHANGELOG.md +++ b/examples/json/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-json +## 4.0.7 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 4.0.6 ### Patch Changes diff --git a/examples/json/package.json b/examples/json/package.json index d244ea7b2bd..683425f4541 100644 --- a/examples/json/package.json +++ b/examples/json/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-json-field", - "version": "4.0.6", + "version": "4.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/json/schema.graphql b/examples/json/schema.graphql index 32862af1084..d474f50471c 100644 --- a/examples/json/schema.graphql +++ b/examples/json/schema.graphql @@ -9,24 +9,55 @@ type Package { input PackageWhereInput { AND: [PackageWhereInput!] OR: [PackageWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - isPrivate: Boolean - isPrivate_not: Boolean + NOT: [PackageWhereInput!] + id: IDFilter + label: StringNullableFilter + isPrivate: BooleanNullableFilter ownedBy: PersonWhereInput - ownedBy_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter } input PackageWhereUniqueInput { @@ -80,7 +111,7 @@ type Person { packages( where: PackageWhereInput! = {} orderBy: [PackageOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Package!] packagesCount(where: PackageWhereInput! = {}): Int @@ -89,23 +120,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - packages_every: PackageWhereInput - packages_some: PackageWhereInput - packages_none: PackageWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + packages: PackageManyRelationFilter +} + +input PackageManyRelationFilter { + every: PackageWhereInput + some: PackageWhereInput + none: PackageWhereInput } input PersonWhereUniqueInput { @@ -174,7 +198,7 @@ type Query { packages( where: PackageWhereInput! = {} orderBy: [PackageOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Package!] package(where: PackageWhereUniqueInput!): Package @@ -182,7 +206,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/task-manager/CHANGELOG.md b/examples/task-manager/CHANGELOG.md index b47181e5bc2..7ffa163a889 100644 --- a/examples/task-manager/CHANGELOG.md +++ b/examples/task-manager/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-task-manager +## 4.0.6 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 4.0.5 ### Patch Changes diff --git a/examples/task-manager/package.json b/examples/task-manager/package.json index 3a63680b98d..8680a007e74 100644 --- a/examples/task-manager/package.json +++ b/examples/task-manager/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-task-manager", - "version": "4.0.5", + "version": "4.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/task-manager/schema.graphql b/examples/task-manager/schema.graphql index 49a0f225167..e194b7cb406 100644 --- a/examples/task-manager/schema.graphql +++ b/examples/task-manager/schema.graphql @@ -16,36 +16,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -103,7 +142,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -112,23 +151,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,7 +226,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -202,7 +234,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/examples/testing/CHANGELOG.md b/examples/testing/CHANGELOG.md index d858f6edfc1..2b4114cecb1 100644 --- a/examples/testing/CHANGELOG.md +++ b/examples/testing/CHANGELOG.md @@ -1,5 +1,20 @@ # @keystone-next/example-testing +## 0.0.6 + +### Patch Changes + +- [#6218](https://github.com/keystonejs/keystone/pull/6218) [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2) Thanks [@timleslie](https://github.com/timleslie)! - Added more details to validation failure error messages. + +* [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +* Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + - @keystone-next/auth@31.0.0 + - @keystone-next/testing@1.1.1 + ## 0.0.5 ### Patch Changes diff --git a/examples/testing/package.json b/examples/testing/package.json index 5baaa7a8735..e094b5328f9 100644 --- a/examples/testing/package.json +++ b/examples/testing/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-testing", - "version": "0.0.5", + "version": "0.0.6", "private": true, "license": "MIT", "scripts": { @@ -10,14 +10,14 @@ "test": "jest --runInBand --testTimeout=60000" }, "dependencies": { - "@babel/core": "^7.14.8", - "@babel/preset-env": "^7.14.9", - "@babel/preset-typescript": "^7.14.5", - "@keystone-next/auth": "^30.0.0", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/testing": "^1.1.0", - "@keystone-next/types": "^23.0.0" + "@babel/core": "^7.15.0", + "@babel/preset-env": "^7.15.0", + "@babel/preset-typescript": "^7.15.0", + "@keystone-next/auth": "^31.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/testing": "^1.1.1", + "@keystone-next/types": "^24.0.0" }, "devDependencies": { "babel-jest": "^27.0.6", diff --git a/examples/testing/schema.graphql b/examples/testing/schema.graphql index 8a707c22288..c6a5ddc8586 100644 --- a/examples/testing/schema.graphql +++ b/examples/testing/schema.graphql @@ -1,3 +1,56 @@ +input CreateInitialPersonInput { + name: String + email: String + password: String +} + +type Mutation { + createInitialPerson( + data: CreateInitialPersonInput! + ): PersonAuthenticationWithPasswordSuccess! + authenticatePersonWithPassword( + email: String! + password: String! + ): PersonAuthenticationWithPasswordResult! + createTask(data: TaskCreateInput!): Task + createTasks(data: [TaskCreateInput!]!): [Task] + updateTask(where: TaskWhereUniqueInput!, data: TaskUpdateInput!): Task + updateTasks(data: [TaskUpdateArgs!]!): [Task] + deleteTask(where: TaskWhereUniqueInput!): Task + deleteTasks(where: [TaskWhereUniqueInput!]!): [Task] + createPerson(data: PersonCreateInput!): Person + createPeople(data: [PersonCreateInput!]!): [Person] + updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person + updatePeople(data: [PersonUpdateArgs!]!): [Person] + deletePerson(where: PersonWhereUniqueInput!): Person + deletePeople(where: [PersonWhereUniqueInput!]!): [Person] + endSession: Boolean! +} + +union AuthenticatedItem = Person + +union PersonAuthenticationWithPasswordResult = + PersonAuthenticationWithPasswordSuccess + | PersonAuthenticationWithPasswordFailure + +type PersonAuthenticationWithPasswordSuccess { + sessionToken: String! + item: Person! +} + +type PersonAuthenticationWithPasswordFailure { + code: PasswordAuthErrorCode! + message: String! +} + +enum PasswordAuthErrorCode { + FAILURE + IDENTITY_NOT_FOUND + SECRET_NOT_SET + MULTIPLE_IDENTITY_MATCHES + SECRET_MISMATCH +} + type Task { id: ID! label: String @@ -16,36 +69,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -105,7 +197,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -118,30 +210,22 @@ type PasswordState { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - password_is_set: Boolean - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + password: PasswordFilter + tasks: TaskManyRelationFilter +} + +input PasswordFilter { + isSet: Boolean! +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,64 +278,12 @@ scalar JSON url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" ) -type Mutation { - createTask(data: TaskCreateInput!): Task - createTasks(data: [TaskCreateInput!]!): [Task] - updateTask(where: TaskWhereUniqueInput!, data: TaskUpdateInput!): Task - updateTasks(data: [TaskUpdateArgs!]!): [Task] - deleteTask(where: TaskWhereUniqueInput!): Task - deleteTasks(where: [TaskWhereUniqueInput!]!): [Task] - createPerson(data: PersonCreateInput!): Person - createPeople(data: [PersonCreateInput!]!): [Person] - updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person - updatePeople(data: [PersonUpdateArgs!]!): [Person] - deletePerson(where: PersonWhereUniqueInput!): Person - deletePeople(where: [PersonWhereUniqueInput!]!): [Person] - authenticatePersonWithPassword( - email: String! - password: String! - ): PersonAuthenticationWithPasswordResult! - createInitialPerson( - data: CreateInitialPersonInput! - ): PersonAuthenticationWithPasswordSuccess! - endSession: Boolean! -} - -union AuthenticatedItem = Person - -union PersonAuthenticationWithPasswordResult = - PersonAuthenticationWithPasswordSuccess - | PersonAuthenticationWithPasswordFailure - -type PersonAuthenticationWithPasswordSuccess { - sessionToken: String! - item: Person! -} - -type PersonAuthenticationWithPasswordFailure { - code: PasswordAuthErrorCode! - message: String! -} - -enum PasswordAuthErrorCode { - FAILURE - IDENTITY_NOT_FOUND - SECRET_NOT_SET - MULTIPLE_IDENTITY_MATCHES - SECRET_MISMATCH -} - -input CreateInitialPersonInput { - name: String - email: String - password: String -} - type Query { + authenticatedItem: AuthenticatedItem tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -259,12 +291,11 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person peopleCount(where: PersonWhereInput! = {}): Int - authenticatedItem: AuthenticatedItem keystone: KeystoneMeta! } diff --git a/examples/virtual-field/CHANGELOG.md b/examples/virtual-field/CHANGELOG.md index 7a25ade4858..87b027c8237 100644 --- a/examples/virtual-field/CHANGELOG.md +++ b/examples/virtual-field/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-virtual-field +## 0.1.4 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + ## 0.1.3 ### Patch Changes diff --git a/examples/virtual-field/README.md b/examples/virtual-field/README.md index 71b53de5e52..fd452f6068f 100644 --- a/examples/virtual-field/README.md +++ b/examples/virtual-field/README.md @@ -108,7 +108,7 @@ relatedPosts: virtual({ // this could have some logic to get posts that are actually related to this one somehow // this is a just a naive "get the three latest posts that aren't this one" return context.db.lists.Post.findMany({ - first: 3, + take: 3, where: { id_not: item.id, status: 'published' }, orderBy: [{ publishDate: 'desc' }], }); diff --git a/examples/virtual-field/package.json b/examples/virtual-field/package.json index c457d83ce4b..6744cd3dc4e 100644 --- a/examples/virtual-field/package.json +++ b/examples/virtual-field/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-virtual-field", - "version": "0.1.3", + "version": "0.1.4", "private": true, "license": "MIT", "scripts": { @@ -9,9 +9,9 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/virtual-field/schema.graphql b/examples/virtual-field/schema.graphql index 70b0feee8a5..2a1713840d0 100644 --- a/examples/virtual-field/schema.graphql +++ b/examples/virtual-field/schema.graphql @@ -25,40 +25,70 @@ type PostCounts { input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] - status: PostStatusType - status_not: PostStatusType - status_in: [PostStatusType] - status_not_in: [PostStatusType] - content: String - content_not: String - content_contains: String - content_not_contains: String - content_in: [String] - content_not_in: [String] - publishDate: String - publishDate_not: String - publishDate_lt: String - publishDate_lte: String - publishDate_gt: String - publishDate_gte: String - publishDate_in: [String] - publishDate_not_in: [String] + NOT: [PostWhereInput!] + id: IDFilter + title: StringNullableFilter + status: PostStatusTypeNullableFilter + content: StringNullableFilter + publishDate: DateTimeNullableFilter author: AuthorWhereInput - author_is_null: Boolean +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input PostStatusTypeNullableFilter { + equals: PostStatusType + in: [PostStatusType!] + notIn: [PostStatusType!] + not: PostStatusTypeNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input PostWhereUniqueInput { @@ -117,7 +147,7 @@ type Author { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int @@ -127,29 +157,17 @@ type Author { input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - posts_every: PostWhereInput - posts_some: PostWhereInput - posts_none: PostWhereInput + NOT: [AuthorWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + posts: PostManyRelationFilter +} + +input PostManyRelationFilter { + every: PostWhereInput + some: PostWhereInput + none: PostWhereInput } input AuthorWhereUniqueInput { @@ -219,7 +237,7 @@ type Query { posts( where: PostWhereInput! = {} orderBy: [PostOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Post!] post(where: PostWhereUniqueInput!): Post @@ -227,7 +245,7 @@ type Query { authors( where: AuthorWhereInput! = {} orderBy: [AuthorOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Author!] author(where: AuthorWhereUniqueInput!): Author diff --git a/examples/virtual-field/schema.ts b/examples/virtual-field/schema.ts index c96eb7ead8b..3dbba311fae 100644 --- a/examples/virtual-field/schema.ts +++ b/examples/virtual-field/schema.ts @@ -102,7 +102,7 @@ export const lists = createSchema({ where: { id: item.id.toString() }, query: `posts( orderBy: { publishDate: desc } - first: 1 + take: 1 ) { id }`, }); if (posts.length > 0) { diff --git a/examples/with-auth/CHANGELOG.md b/examples/with-auth/CHANGELOG.md index e582c7673a6..e179b27cebf 100644 --- a/examples/with-auth/CHANGELOG.md +++ b/examples/with-auth/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-next/example-with-auth +## 2.0.7 + +### Patch Changes + +- [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/auth@31.0.0 + ## 2.0.6 ### Patch Changes diff --git a/examples/with-auth/package.json b/examples/with-auth/package.json index e9caf46bbde..a9cefb11b89 100644 --- a/examples/with-auth/package.json +++ b/examples/with-auth/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-with-auth", - "version": "2.0.6", + "version": "2.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,9 +9,9 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/auth": "^30.0.0", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/auth": "^31.0.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/examples/with-auth/schema.graphql b/examples/with-auth/schema.graphql index 8a707c22288..c6a5ddc8586 100644 --- a/examples/with-auth/schema.graphql +++ b/examples/with-auth/schema.graphql @@ -1,3 +1,56 @@ +input CreateInitialPersonInput { + name: String + email: String + password: String +} + +type Mutation { + createInitialPerson( + data: CreateInitialPersonInput! + ): PersonAuthenticationWithPasswordSuccess! + authenticatePersonWithPassword( + email: String! + password: String! + ): PersonAuthenticationWithPasswordResult! + createTask(data: TaskCreateInput!): Task + createTasks(data: [TaskCreateInput!]!): [Task] + updateTask(where: TaskWhereUniqueInput!, data: TaskUpdateInput!): Task + updateTasks(data: [TaskUpdateArgs!]!): [Task] + deleteTask(where: TaskWhereUniqueInput!): Task + deleteTasks(where: [TaskWhereUniqueInput!]!): [Task] + createPerson(data: PersonCreateInput!): Person + createPeople(data: [PersonCreateInput!]!): [Person] + updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person + updatePeople(data: [PersonUpdateArgs!]!): [Person] + deletePerson(where: PersonWhereUniqueInput!): Person + deletePeople(where: [PersonWhereUniqueInput!]!): [Person] + endSession: Boolean! +} + +union AuthenticatedItem = Person + +union PersonAuthenticationWithPasswordResult = + PersonAuthenticationWithPasswordSuccess + | PersonAuthenticationWithPasswordFailure + +type PersonAuthenticationWithPasswordSuccess { + sessionToken: String! + item: Person! +} + +type PersonAuthenticationWithPasswordFailure { + code: PasswordAuthErrorCode! + message: String! +} + +enum PasswordAuthErrorCode { + FAILURE + IDENTITY_NOT_FOUND + SECRET_NOT_SET + MULTIPLE_IDENTITY_MATCHES + SECRET_MISMATCH +} + type Task { id: ID! label: String @@ -16,36 +69,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -105,7 +197,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -118,30 +210,22 @@ type PasswordState { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - email: String - email_not: String - email_contains: String - email_not_contains: String - email_in: [String] - email_not_in: [String] - password_is_set: Boolean - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + email: StringNullableFilter + password: PasswordFilter + tasks: TaskManyRelationFilter +} + +input PasswordFilter { + isSet: Boolean! +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,64 +278,12 @@ scalar JSON url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" ) -type Mutation { - createTask(data: TaskCreateInput!): Task - createTasks(data: [TaskCreateInput!]!): [Task] - updateTask(where: TaskWhereUniqueInput!, data: TaskUpdateInput!): Task - updateTasks(data: [TaskUpdateArgs!]!): [Task] - deleteTask(where: TaskWhereUniqueInput!): Task - deleteTasks(where: [TaskWhereUniqueInput!]!): [Task] - createPerson(data: PersonCreateInput!): Person - createPeople(data: [PersonCreateInput!]!): [Person] - updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person - updatePeople(data: [PersonUpdateArgs!]!): [Person] - deletePerson(where: PersonWhereUniqueInput!): Person - deletePeople(where: [PersonWhereUniqueInput!]!): [Person] - authenticatePersonWithPassword( - email: String! - password: String! - ): PersonAuthenticationWithPasswordResult! - createInitialPerson( - data: CreateInitialPersonInput! - ): PersonAuthenticationWithPasswordSuccess! - endSession: Boolean! -} - -union AuthenticatedItem = Person - -union PersonAuthenticationWithPasswordResult = - PersonAuthenticationWithPasswordSuccess - | PersonAuthenticationWithPasswordFailure - -type PersonAuthenticationWithPasswordSuccess { - sessionToken: String! - item: Person! -} - -type PersonAuthenticationWithPasswordFailure { - code: PasswordAuthErrorCode! - message: String! -} - -enum PasswordAuthErrorCode { - FAILURE - IDENTITY_NOT_FOUND - SECRET_NOT_SET - MULTIPLE_IDENTITY_MATCHES - SECRET_MISMATCH -} - -input CreateInitialPersonInput { - name: String - email: String - password: String -} - type Query { + authenticatedItem: AuthenticatedItem tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -259,12 +291,11 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person peopleCount(where: PersonWhereInput! = {}): Int - authenticatedItem: AuthenticatedItem keystone: KeystoneMeta! } diff --git a/package.json b/package.json index 7cf3046e78c..0cbf8275d20 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "lint:prettier": "prettier --list-different \"**/*.{js,json,ts,tsx}\"", "lint:markdown": "remark . --frail --quiet", "lint:types": "tsc", - "lint": "yarn lint:prettier && yarn lint:eslint && yarn lint:markdown && yarn lint:types", + "lint": "yarn lint:prettier && yarn lint:eslint && yarn lint:markdown && yarn lint:types && yarn lint:filters", "test": "yarn lint && yarn test:unit", "test:unit": "cross-env DISABLE_LOGGING=true NODE_ENV=test jest --no-watchman --runInBand --logHeapUsage", "test:unit:debug": "cross-env NODE_ENV=test node --inspect-brk `which jest` --runInBand", @@ -35,17 +35,19 @@ "update": "manypkg upgrade", "no-cypress-install": "cross-env CYPRESS_INSTALL_BINARY=0 yarn", "postinstall-examples": "for d in `find examples -type d -maxdepth 1 -mindepth 1`; do cd $d; yarn keystone-next postinstall --fix; cd ../..; done; for d in `find examples-staging -type d -maxdepth 1 -mindepth 1`; do cd $d; yarn keystone-next postinstall --fix; cd ../..; done; for d in `find tests/test-projects -type d -maxdepth 1 -mindepth 1`; do cd $d; yarn keystone-next postinstall --fix; cd ../..; done", - "lint:examples": "for d in `find examples -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done; for d in `find examples-staging -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done; for d in `find tests/test-projects -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done" + "lint:examples": "for d in `find examples -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done; for d in `find examples-staging -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done; for d in `find tests/test-projects -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../../..; done", + "generate-filters": "cd prisma-utils && yarn generate", + "lint:filters": "cd prisma-utils && yarn verify" }, "dependencies": { - "@babel/core": "^7.14.8", + "@babel/core": "^7.15.0", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.14.5", - "@babel/preset-env": "^7.14.9", + "@babel/plugin-transform-runtime": "^7.15.0", + "@babel/preset-env": "^7.15.0", "@babel/preset-react": "^7.14.5", - "@babel/preset-typescript": "^7.14.5", + "@babel/preset-typescript": "^7.15.0", "@changesets/changelog-github": "^0.4.0", "@changesets/cli": "^2.16.0", "@jest/test-sequencer": "^27.0.6", @@ -53,15 +55,15 @@ "@preconstruct/cli": "2.1.0", "@preconstruct/eslint-plugin-format-js-tag": "^0.1.0", "@testing-library/jest-dom": "^5.14.1", - "@types/jest": "^26.0.24", + "@types/jest": "^27.0.1", "@types/node-fetch": "^2.5.12", - "@typescript-eslint/eslint-plugin": "^4.29.0", - "@typescript-eslint/parser": "^4.29.0", + "@typescript-eslint/eslint-plugin": "^4.29.2", + "@typescript-eslint/parser": "^4.29.2", "chalk-cli": "^4.1.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", "eslint-plugin-cypress": "^2.11.3", - "eslint-plugin-import": "^2.23.3", + "eslint-plugin-import": "^2.24.0", "eslint-plugin-jest": "^24.4.0", "eslint-plugin-react": "^7.24.0", "eslint-plugin-react-hooks": "^4.2.0", @@ -117,7 +119,8 @@ "tests/api-tests", "tests/benchmarks", "tests/examples-smoke-tests", - "tests/test-projects/*" + "tests/test-projects/*", + "prisma-utils" ], "nohoist": [ "**/cypress-multi-reporters" @@ -126,7 +129,8 @@ "preconstruct": { "packages": [ "packages/*", - "design-system/packages/*" + "design-system/packages/*", + "prisma-utils" ], "distFilenameStrategy": "unscoped-package-name" }, diff --git a/packages/admin-ui-utils/CHANGELOG.md b/packages/admin-ui-utils/CHANGELOG.md index b196a6d926c..5acd3fcae8d 100644 --- a/packages/admin-ui-utils/CHANGELOG.md +++ b/packages/admin-ui-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @keystone-next/admin-ui-utils +## 5.0.6 + +### Patch Changes + +- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/types@24.0.0 + ## 5.0.5 ### Patch Changes diff --git a/packages/admin-ui-utils/package.json b/packages/admin-ui-utils/package.json index 23e2be5e864..9a0ba81f77b 100644 --- a/packages/admin-ui-utils/package.json +++ b/packages/admin-ui-utils/package.json @@ -1,15 +1,15 @@ { "name": "@keystone-next/admin-ui-utils", - "version": "5.0.5", + "version": "5.0.6", "main": "dist/admin-ui-utils.cjs.js", "module": "dist/admin-ui-utils.esm.js", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/types": "^23.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/core": "^3.1.1", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "fast-deep-equal": "^3.1.3", "graphql": "^15.5.1" }, diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index 996a127bd09..a37f9e59522 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,36 @@ # @keystone-next/auth +## 31.0.0 + +### Major Changes + +- [#6211](https://github.com/keystonejs/keystone/pull/6211) [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. + + If you have a list called `Item`, the update mutations now look like this: + + ```graphql + type Mutation { + updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item + updateItems(data: [ItemUpdateArgs!]!): [Item] + } + + input ItemUpdateArgs { + where: ItemWhereUniqueInput! + data: ItemUpdateInput! + } + ``` + +### Patch Changes + +- [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`c2bb6a9a5`](https://github.com/keystonejs/keystone/commit/c2bb6a9a596fc52a3c61ec5d91c79758e417e61d), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + - @keystone-ui/notice@4.0.1 + - @keystone-next/admin-ui-utils@5.0.6 + ## 30.0.0 ### Major Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index d02646024d2..1021aa7ca09 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/auth", - "version": "30.0.0", + "version": "31.0.0", "license": "MIT", "main": "dist/auth.cjs.js", "module": "dist/auth.esm.js", @@ -8,25 +8,25 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.14.8", - "@graphql-tools/merge": "^6.2.16", - "@keystone-next/admin-ui-utils": "^5.0.5", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/types": "^23.0.0", + "@babel/runtime": "^7.15.3", + "@graphql-tools/schema": "^8.1.1", + "@keystone-next/admin-ui-utils": "^5.0.6", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.1.1", "@keystone-ui/fields": "^4.1.1", - "@keystone-ui/notice": "^4.0.0", + "@keystone-ui/notice": "^4.0.1", "cross-fetch": "^3.1.4", "fast-deep-equal": "^3.1.3", "graphql": "^15.5.1" }, "devDependencies": { - "@keystone-next/keystone": "^23.0.0", + "@keystone-next/keystone": "^24.0.0", "react": "^17.0.2" }, "peerDependencies": { - "@keystone-next/keystone": "^23.0.0", + "@keystone-next/keystone": "^24.0.0", "react": "^17.0.2" }, "preconstruct": { diff --git a/packages/auth/src/schema.ts b/packages/auth/src/schema.ts index bc78ec3fd19..64cbef1e917 100644 --- a/packages/auth/src/schema.ts +++ b/packages/auth/src/schema.ts @@ -1,4 +1,4 @@ -import { mergeSchemas } from '@graphql-tools/merge'; +import { mergeSchemas } from '@graphql-tools/schema'; import { ExtendGraphqlSchema } from '@keystone-next/types'; import { diff --git a/packages/cloudinary/CHANGELOG.md b/packages/cloudinary/CHANGELOG.md index bdc6d3709d8..2ccbf371910 100644 --- a/packages/cloudinary/CHANGELOG.md +++ b/packages/cloudinary/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/cloudinary +## 6.0.6 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/types@24.0.0 + ## 6.0.5 ### Patch Changes diff --git a/packages/cloudinary/package.json b/packages/cloudinary/package.json index 85814f1e951..5b96740dc23 100644 --- a/packages/cloudinary/package.json +++ b/packages/cloudinary/package.json @@ -1,18 +1,18 @@ { "name": "@keystone-next/cloudinary", - "version": "6.0.5", + "version": "6.0.6", "license": "MIT", "main": "dist/cloudinary.cjs.js", "module": "dist/cloudinary.esm.js", "dependencies": { - "@babel/runtime": "^7.14.8", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/types": "^23.0.0", + "@babel/runtime": "^7.15.3", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.1.1", "@keystone-ui/fields": "^4.1.2", "@keystone-ui/pill": "^5.0.0", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "cloudinary": "^1.26.3", "cuid": "^2.1.8", "graphql-upload": "^12.0.0", diff --git a/packages/fields-document/CHANGELOG.md b/packages/fields-document/CHANGELOG.md index f76d4cb0624..dae1a7275d3 100644 --- a/packages/fields-document/CHANGELOG.md +++ b/packages/fields-document/CHANGELOG.md @@ -1,5 +1,40 @@ # @keystone-next/fields-document +## 8.0.0 + +### Major Changes + +- [#6095](https://github.com/keystonejs/keystone/pull/6095) [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information. + + ```graphql + query { + posts(where: { title: { contains: "Something" } }) { + title + content + } + } + ``` + +### Patch Changes + +- [#6250](https://github.com/keystonejs/keystone/pull/6250) [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450) Thanks [@timleslie](https://github.com/timleslie)! - Updated internal type definitions. + +* [#6318](https://github.com/keystonejs/keystone/pull/6318) [`e985aa010`](https://github.com/keystonejs/keystone/commit/e985aa0104d30a779f21ec05d80e6b98ece87dfb) Thanks [@raveling](https://github.com/raveling)! - Updated the document editor's expanded view so that you can click on any of the empty space below the content to focus the editor + +- [#6207](https://github.com/keystonejs/keystone/pull/6207) [`69f47bfed`](https://github.com/keystonejs/keystone/commit/69f47bfed1eaa1269cfdc42071268a914bd4aa17) Thanks [@timleslie](https://github.com/timleslie)! - Suppressed error logging during tests. + +* [#6197](https://github.com/keystonejs/keystone/pull/6197) [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. + + If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. + + Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. + +* Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + - @keystone-next/admin-ui-utils@5.0.6 + ## 7.0.3 ### Patch Changes diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index fa2373d04ca..5484772ac8f 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -1,7 +1,7 @@ { "name": "@keystone-next/fields-document", "description": "KeystoneJS Document Field Type", - "version": "7.0.3", + "version": "8.0.0", "main": "dist/fields-document.cjs.js", "module": "dist/fields-document.esm.js", "files": [ @@ -19,20 +19,20 @@ ] }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@braintree/sanitize-url": "^5.0.2", "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/admin-ui-utils": "^5.0.5", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", + "@keystone-next/admin-ui-utils": "^5.0.6", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.1.1", "@keystone-ui/fields": "^4.1.1", "@keystone-ui/icons": "^4.0.0", "@keystone-ui/popover": "^4.0.1", "@keystone-ui/tooltip": "^4.0.1", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "apply-ref": "^1.0.0", "fp-ts": "^2.11.1", "graphql": "^15.5.1", diff --git a/packages/fields-document/src/DocumentEditor/index.tsx b/packages/fields-document/src/DocumentEditor/index.tsx index 1a698698273..f68c89d7fef 100644 --- a/packages/fields-document/src/DocumentEditor/index.tsx +++ b/packages/fields-document/src/DocumentEditor/index.tsx @@ -226,7 +226,7 @@ export function DocumentEditor({ documentFeatures: DocumentFeatures; }) { const isShiftPressedRef = useKeyDownRef('Shift'); - const { colors } = useTheme(); + const { colors, spacing } = useTheme(); const [expanded, setExpanded] = useState(false); const editor = useMemo( () => createDocumentEditor(documentFeatures, componentBlocks, relationships, isShiftPressedRef), @@ -235,7 +235,11 @@ export function DocumentEditor({ return (
    + + { // for debugging false && @@ -345,9 +359,11 @@ export function DocumentEditorProvider({ export function DocumentEditorEditable({ autoFocus, readOnly, + className, }: { autoFocus?: boolean; readOnly?: boolean; + className?: string; }) { const editor = useSlate(); const componentBlocks = useContext(ComponentBlockContext); @@ -401,6 +417,7 @@ export function DocumentEditorEditable({ readOnly={readOnly} renderElement={renderElement} renderLeaf={renderLeaf} + className={className} /> ); } @@ -429,7 +446,9 @@ function Debugger() { const orderedListStyles = ['lower-roman', 'decimal', 'lower-alpha']; const unorderedListStyles = ['square', 'disc', 'circle']; -let styles: any = {}; +let styles: any = { + flex: 1, +}; let listDepth = 10; diff --git a/packages/fields-document/src/relationship-data.tsx b/packages/fields-document/src/relationship-data.tsx index 553ab970fab..ede96091c09 100644 --- a/packages/fields-document/src/relationship-data.tsx +++ b/packages/fields-document/src/relationship-data.tsx @@ -27,7 +27,7 @@ export function addRelationshipData( let val = await graphQLAPI.run({ query: `query($ids: [ID!]!) {items:${ gqlNames(relationship.listKey).listQueryName - }(where: {id_in:$ids}) {${idFieldAlias}:id ${labelFieldAlias}:${labelField}\n${ + }(where: { id: { in: $ids } }) {${idFieldAlias}:id ${labelFieldAlias}:${labelField}\n${ relationship.selection || '' }}}`, variables: { ids }, diff --git a/packages/fields/CHANGELOG.md b/packages/fields/CHANGELOG.md index 22b049863d6..cafa88f5de0 100644 --- a/packages/fields/CHANGELOG.md +++ b/packages/fields/CHANGELOG.md @@ -1,5 +1,122 @@ # @keystone-next/fields +## 14.0.0 + +### Major Changes + +- [#6280](https://github.com/keystonejs/keystone/pull/6280) [`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `gqlType` option to `autoIncrement` field type. The field type will now always be represented with an `Int` in GraphQL + +* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `_ListKeyMeta` and `_toManyRelationshipFieldMeta` fields. You should use `listKeyCount` and `toManyRelationshipFieldCount` instead + +- [#6266](https://github.com/keystonejs/keystone/pull/6266) [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Renamed `first` argument in find many queries to `take` to align with Prisma. + + ```graphql + type Query { + users( + where: UserWhereInput! = {} + orderBy: [UserOrderByInput!]! = [] + # previously was first: Int + take: Int + skip: Int! = 0 + ): [User!] + # ... + } + + type User { + # ... + posts( + where: PostWhereInput! = {} + orderBy: [PostOrderByInput!]! = [] + # previously was first: Int + take: Int + skip: Int! = 0 + ): [Post!] + # ... + } + ``` + +* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `search` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `contains` filters instead. + +- [#6095](https://github.com/keystonejs/keystone/pull/6095) [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information. + + ```graphql + query { + posts(where: { title: { contains: "Something" } }) { + title + content + } + } + ``` + +* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `sortBy` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `orderBy` instead. + +- [#6217](https://github.com/keystonejs/keystone/pull/6217) [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been renamed to `disconnect` in to-one relationship inputs and the old `disconnect` field has been removed. There are also seperate input types for create and update where the input for create doesn't have `disconnect`. It's also now required that if you provide a to-one relationship input, you must provide exactly one field to the input. + + If you have a list called `Item`, the to-one relationship inputs now look like this: + + ```graphql + input ItemRelateToOneForCreateInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + } + input ItemRelateToOneForUpdateInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + disconnect: Boolean + } + ``` + +* [#6224](https://github.com/keystonejs/keystone/pull/6224) [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been replaced by `set` in to-many relationship inputs, the equivalent to `disconnectAll: true` is now `set: []`. There are also seperate input types for create and update where the input for create doesn't have `disconnect` or `set`. The inputs in the lists in the input field are now also non-null. + + If you have a list called `Item`, the to-many relationship inputs now look like this: + + ```graphql + input ItemRelateToManyForCreateInput { + create: [ItemCreateInput!] + connect: [ItemWhereUniqueInput!] + } + input ItemRelateToManyForUpdateInput { + disconnect: [ItemWhereUniqueInput!] + set: [ItemWhereUniqueInput!] + create: [ItemCreateInput!] + connect: [ItemWhereUniqueInput!] + } + ``` + +- [#6211](https://github.com/keystonejs/keystone/pull/6211) [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. + + If you have a list called `Item`, the update mutations now look like this: + + ```graphql + type Mutation { + updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item + updateItems(data: [ItemUpdateArgs!]!): [Item] + } + + input ItemUpdateArgs { + where: ItemWhereUniqueInput! + data: ItemUpdateInput! + } + ``` + +### Patch Changes + +- [#6237](https://github.com/keystonejs/keystone/pull/6237) [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Updated timestamp field to default time to 00:00 when no time is selected. + +* [#6197](https://github.com/keystonejs/keystone/pull/6197) [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. + + If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. + + Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. + +* Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`c2bb6a9a5`](https://github.com/keystonejs/keystone/commit/c2bb6a9a596fc52a3c61ec5d91c79758e417e61d), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`6cd7ab78e`](https://github.com/keystonejs/keystone/commit/6cd7ab78e018fa0ffaddc1258426d23da19cd854), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/keystone@24.0.0 + - @keystone-next/types@24.0.0 + - @keystone-ui/toast@4.0.2 + - @keystone-ui/segmented-control@4.0.2 + - @keystone-next/admin-ui-utils@5.0.6 + - @keystone-next/utils@1.0.4 + ## 13.0.0 ### Major Changes diff --git a/packages/fields/package.json b/packages/fields/package.json index 3252816db45..27336167293 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/fields", - "version": "13.0.0", + "version": "14.0.0", "license": "MIT", "main": "dist/fields.cjs.js", "module": "dist/fields.esm.js", @@ -11,11 +11,11 @@ "mime": "^2.5.2" }, "dependencies": { - "@babel/runtime": "^7.14.8", - "@keystone-next/admin-ui-utils": "^5.0.5", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/types": "^23.0.0", - "@keystone-next/utils": "^1.0.3", + "@babel/runtime": "^7.15.3", + "@keystone-next/admin-ui-utils": "^5.0.6", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/types": "^24.0.0", + "@keystone-next/utils": "^1.0.4", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.1.1", "@keystone-ui/fields": "^4.1.2", @@ -23,11 +23,11 @@ "@keystone-ui/loading": "^4.0.0", "@keystone-ui/modals": "^4.0.0", "@keystone-ui/pill": "^5.0.0", - "@keystone-ui/segmented-control": "^4.0.1", - "@keystone-ui/toast": "^4.0.1", + "@keystone-ui/segmented-control": "^4.0.2", + "@keystone-ui/toast": "^4.0.2", "@keystone-ui/tooltip": "^4.0.1", "@types/bcryptjs": "^2.4.2", - "@types/react": "^17.0.15", + "@types/react": "^17.0.18", "bcryptjs": "^2.4.3", "bytes": "^3.1.0", "copy-to-clipboard": "^3.3.1", diff --git a/packages/fields/src/tests/test-fixtures.ts b/packages/fields/src/tests/test-fixtures.ts index b83e5225be1..0c72dadf71c 100644 --- a/packages/fields/src/tests/test-fixtures.ts +++ b/packages/fields/src/tests/test-fixtures.ts @@ -63,20 +63,20 @@ export const filterTests = (withKeystone: any) => { ); test( - 'Filter: id', + 'Filter: equals', withKeystone(async ({ context }: { context: KeystoneContext }) => { const IDs = await getIDs(context); const id = IDs['person2']; - return match(context, { id }, [{ id: IDs['person2'], name: 'person2' }]); + return match(context, { id: { equals: id } }, [{ id: IDs['person2'], name: 'person2' }]); }) ); test( - 'Filter: id_not', + 'Filter: not equals', withKeystone(async ({ context }: { context: KeystoneContext }) => { const IDs = await getIDs(context); const id = IDs['person2']; - return match(context, { id_not: id }, [ + return match(context, { id: { not: { equals: id } } }, [ { id: IDs['person1'], name: 'person1' }, { id: IDs['person3'], name: 'person3' }, { id: IDs['person4'], name: 'person4' }, @@ -85,12 +85,12 @@ export const filterTests = (withKeystone: any) => { ); test( - 'Filter: id_in', + 'Filter: in', withKeystone(async ({ context }: { context: KeystoneContext }) => { const IDs = await getIDs(context); const id2 = IDs['person2']; const id3 = IDs['person3']; - return match(context, { id_in: [id2, id3] }, [ + return match(context, { id: { in: [id2, id3] } }, [ { id: IDs['person2'], name: 'person2' }, { id: IDs['person3'], name: 'person3' }, ]); @@ -98,27 +98,27 @@ export const filterTests = (withKeystone: any) => { ); test( - 'Filter: id_in - empty list', + 'Filter: in - empty list', withKeystone(({ context }: { context: KeystoneContext }) => { - return match(context, { id_in: [] }, []); + return match(context, { id: { in: [] } }, []); }) ); test( - 'Filter: id_in - missing id', + 'Filter: in - missing id', withKeystone(({ context }: { context: KeystoneContext }) => { const fakeID = 'cdafasdfasd'; - return match(context, { id_in: [fakeID] }, []); + return match(context, { id: { in: [fakeID] } }, []); }) ); test( - 'Filter: id_not_in', + 'Filter: not in', withKeystone(async ({ context }: { context: KeystoneContext }) => { const IDs = await getIDs(context); const id2 = IDs['person2']; const id3 = IDs['person3']; - return match(context, { id_not_in: [id2, id3] }, [ + return match(context, { id: { not: { in: [id2, id3] } } }, [ { id: IDs['person1'], name: 'person1' }, { id: IDs['person4'], name: 'person4' }, ]); @@ -126,10 +126,10 @@ export const filterTests = (withKeystone: any) => { ); test( - 'Filter: id_not_in - empty list', + 'Filter: not in - empty list', withKeystone(async ({ context }: { context: KeystoneContext }) => { const IDs = await getIDs(context); - return match(context, { id_not_in: [] }, [ + return match(context, { id: { not: { in: [] } } }, [ { id: IDs['person1'], name: 'person1' }, { id: IDs['person2'], name: 'person2' }, { id: IDs['person3'], name: 'person3' }, @@ -139,11 +139,11 @@ export const filterTests = (withKeystone: any) => { ); test( - 'Filter: id_not_in - missing id', + 'Filter: not in - missing id', withKeystone(async ({ context }: { context: KeystoneContext }) => { const IDs = await getIDs(context); const fakeID = 'cdafasdfasd'; - return match(context, { id_not_in: [fakeID] }, [ + return match(context, { id: { not: { in: [fakeID] } } }, [ { id: IDs['person1'], name: 'person1' }, { id: IDs['person2'], name: 'person2' }, { id: IDs['person3'], name: 'person3' }, diff --git a/packages/fields/src/types/autoIncrement/index.ts b/packages/fields/src/types/autoIncrement/index.ts index ceb6ef68e0f..a4484ec6a65 100644 --- a/packages/fields/src/types/autoIncrement/index.ts +++ b/packages/fields/src/types/autoIncrement/index.ts @@ -7,6 +7,7 @@ import { legacyFilters, orderDirectionEnum, schema, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; import { getIndexType } from '../../get-index-type'; @@ -17,7 +18,6 @@ export type AutoIncrementFieldConfig = {}): FieldTypeFunc => meta => { - const type = meta.fieldKey === 'id' || gqlType === 'ID' ? schema.ID : schema.Int; - const __legacy = { - isRequired, - defaultValue, - filters: { - fields: { - ...legacyFilters.fields.equalityInputFields(meta.fieldKey, type), - ...legacyFilters.fields.orderingInputFields(meta.fieldKey, type), - ...legacyFilters.fields.inInputFields(meta.fieldKey, type), - }, - impls: { - ...equalityConditions(meta.fieldKey, x => Number(x) || -1), - ...legacyFilters.impls.orderingConditions(meta.fieldKey, x => Number(x) || -1), - ...inConditions(meta.fieldKey, x => x.map((xx: any) => Number(xx) || -1)), - }, - }, - }; - if (meta.fieldKey === 'id') { - return fieldType({ - kind: 'scalar', - mode: 'required', - scalar: 'Int', - default: { kind: 'autoincrement' }, - })({ - ...config, - input: { - // TODO: fix the fact that TS did not catch that a resolver is needed here - uniqueWhere: { - arg: schema.arg({ type }), - resolve(value) { - return Number(value); - }, - }, - orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, - }, - output: schema.field({ - type: schema.nonNull(schema.ID), - resolve({ value }) { - return value.toString(); - }, - }), - views: resolveView('integer/views'), - __legacy, - }); - } - const inputResolver = (val: number | string | null | undefined) => { - if (val == null) { - return val; - } - return Number(val); - }; return fieldType({ kind: 'scalar', mode: 'optional', @@ -90,20 +38,35 @@ export const autoIncrement = })({ ...config, input: { - uniqueWhere: isUnique ? { arg: schema.arg({ type }), resolve: x => Number(x) } : undefined, - create: { arg: schema.arg({ type }), resolve: inputResolver }, - update: { arg: schema.arg({ type }), resolve: inputResolver }, + where: { + arg: schema.arg({ + type: filters[meta.provider].Int.optional, + }), + resolve: filters.resolveCommon, + }, + uniqueWhere: isUnique ? { arg: schema.arg({ type: schema.Int }) } : undefined, + create: { arg: schema.arg({ type: schema.Int }) }, + update: { arg: schema.arg({ type: schema.Int }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, }, - output: schema.field({ - type, - resolve({ value }) { - if (value === null) return null; - return type === schema.ID ? value.toString() : value; - }, - }), + output: schema.field({ type: schema.Int }), views: resolveView('integer/views'), - __legacy, + __legacy: { + isRequired, + defaultValue, + filters: { + fields: { + ...legacyFilters.fields.equalityInputFields(meta.fieldKey, schema.Int), + ...legacyFilters.fields.orderingInputFields(meta.fieldKey, schema.Int), + ...legacyFilters.fields.inInputFields(meta.fieldKey, schema.Int), + }, + impls: { + ...equalityConditions(meta.fieldKey, x => Number(x) || -1), + ...legacyFilters.impls.orderingConditions(meta.fieldKey, x => Number(x) || -1), + ...inConditions(meta.fieldKey, x => x.map((xx: any) => Number(xx) || -1)), + }, + }, + }, }); }; diff --git a/packages/fields/src/types/autoIncrement/tests/test-fixtures.ts b/packages/fields/src/types/autoIncrement/tests/test-fixtures.ts index 80796704315..c4659c1f360 100644 --- a/packages/fields/src/types/autoIncrement/tests/test-fixtures.ts +++ b/packages/fields/src/types/autoIncrement/tests/test-fixtures.ts @@ -2,13 +2,10 @@ import { KeystoneContext } from '@keystone-next/types'; import { text } from '../../text'; import { autoIncrement } from '..'; -type MatrixValue = typeof testMatrix[number]; - export const name = 'AutoIncrement'; export const typeFunction = autoIncrement; -export const testMatrix = ['ID', 'Int'] as const; -export const exampleValue = (matrixValue: MatrixValue) => (matrixValue === 'ID' ? '35' : 35); -export const exampleValue2 = (matrixValue: MatrixValue) => (matrixValue === 'ID' ? '36' : 36); +export const exampleValue = () => 35; +export const exampleValue2 = () => 36; export const supportsUnique = true; export const fieldName = 'orderNumber'; export const skipCreateTest = false; @@ -16,21 +13,9 @@ export const skipUpdateTest = true; export const unSupportedAdapterList = ['sqlite']; -// Be default, `AutoIncrement` are read-only. But for `isRequired` test purpose, we need to bypass these restrictions. -export const fieldConfig = (matrixValue: MatrixValue) => ({ - gqlType: matrixValue, - access: { create: true, update: true }, -}); - -export const getTestFields = (matrixValue: MatrixValue) => ({ +export const getTestFields = () => ({ name: text(), - orderNumber: autoIncrement({ - // The gqlType argument is not currently available on the type. - // This will be reviewed when we do our full field type API review - // @ts-ignore - gqlType: matrixValue, - access: { create: true }, - }), + orderNumber: autoIncrement(), }); export const initItems = () => { @@ -45,32 +30,20 @@ export const initItems = () => { ]; }; -export const storedValues = (matrixValue: MatrixValue) => - matrixValue === 'ID' - ? [ - { name: 'product1', orderNumber: '1' }, - { name: 'product2', orderNumber: '2' }, - { name: 'product3', orderNumber: '3' }, - { name: 'product4', orderNumber: '4' }, - { name: 'product5', orderNumber: '5' }, - { name: 'product6', orderNumber: '6' }, - { name: 'product7', orderNumber: '7' }, - ] - : [ - { name: 'product1', orderNumber: 1 }, - { name: 'product2', orderNumber: 2 }, - { name: 'product3', orderNumber: 3 }, - { name: 'product4', orderNumber: 4 }, - { name: 'product5', orderNumber: 5 }, - { name: 'product6', orderNumber: 6 }, - { name: 'product7', orderNumber: 7 }, - ]; +export const storedValues = () => [ + { name: 'product1', orderNumber: 1 }, + { name: 'product2', orderNumber: 2 }, + { name: 'product3', orderNumber: 3 }, + { name: 'product4', orderNumber: 4 }, + { name: 'product5', orderNumber: 5 }, + { name: 'product6', orderNumber: 6 }, + { name: 'product7', orderNumber: 7 }, +]; export const supportedFilters = () => []; -export const filterTests = (withKeystone: (arg: any) => any, matrixValue: MatrixValue) => { - const _storedValues = storedValues(matrixValue); - const _f = matrixValue === 'ID' ? (x: any) => x.toString() : (x: any) => x; +export const filterTests = (withKeystone: (arg: any) => any) => { + const _storedValues = storedValues(); const match = async (context: KeystoneContext, where: Record, expected: any[]) => expect( await context.lists.Test.findMany({ @@ -81,93 +54,79 @@ export const filterTests = (withKeystone: (arg: any) => any, matrixValue: Matrix ).toEqual(expected.map(i => _storedValues[i])); test( - 'Filter: orderNumber', - withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber: _f(1) }, [0]) - ) - ); - - test( - 'Filter: orderNumber_not', - withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_not: _f(1) }, [1, 2, 3, 4, 5, 6]) - ) - ); - - test( - 'Filter: orderNumber_not null', + 'Filter: equals', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_not: null }, [0, 1, 2, 3, 4, 5, 6]) + match(context, { orderNumber: { equals: 1 } }, [0]) ) ); test( - 'Filter: orderNumber_lt', + 'Filter: not', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_lt: _f(2) }, [0]) + match(context, { orderNumber: { not: { equals: 1 } } }, [1, 2, 3, 4, 5, 6]) ) ); test( - 'Filter: orderNumber_lte', + 'Filter: not null', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_lte: _f(2) }, [0, 1]) + match(context, { orderNumber: { not: null } }, [0, 1, 2, 3, 4, 5, 6]) ) ); test( - 'Filter: orderNumber_gt', + 'Filter: lt', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_gt: _f(2) }, [2, 3, 4, 5, 6]) + match(context, { orderNumber: { lt: 2 } }, [0]) ) ); test( - 'Filter: orderNumber_gte', + 'Filter: lte', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_gte: _f(2) }, [1, 2, 3, 4, 5, 6]) + match(context, { orderNumber: { lte: 2 } }, [0, 1]) ) ); test( - 'Filter: orderNumber_in (empty list)', + 'Filter: gt', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_in: [] }, []) + match(context, { orderNumber: { gt: 2 } }, [2, 3, 4, 5, 6]) ) ); test( - 'Filter: orderNumber_not_in (empty list)', + 'Filter: gte', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_not_in: [] }, [0, 1, 2, 3, 4, 5, 6]) + match(context, { orderNumber: { gte: 2 } }, [1, 2, 3, 4, 5, 6]) ) ); test( - 'Filter: orderNumber_in', + 'Filter: in (empty list)', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_in: ([1, 2, 3] as const).map(_f) }, [0, 1, 2]) + match(context, { orderNumber: { in: [] } }, []) ) ); test( - 'Filter: orderNumber_not_in', + 'Filter: not in (empty list)', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_not_in: [1, 2, 3].map(_f) }, [3, 4, 5, 6]) + match(context, { orderNumber: { notIn: [] } }, [0, 1, 2, 3, 4, 5, 6]) ) ); test( - 'Filter: orderNumber_in null', + 'Filter: in', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_in: [null] }, []) + match(context, { orderNumber: { in: [1, 2, 3] } }, [0, 1, 2]) ) ); test( - 'Filter: orderNumber_not_in null', + 'Filter: not in', withKeystone(({ context }: { context: KeystoneContext }) => - match(context, { orderNumber_not_in: [null] }, [0, 1, 2, 3, 4, 5, 6]) + match(context, { orderNumber: { notIn: [1, 2, 3] } }, [3, 4, 5, 6]) ) ); }; diff --git a/packages/fields/src/types/checkbox/index.ts b/packages/fields/src/types/checkbox/index.ts index 1e320de29a6..dd2b36fb891 100644 --- a/packages/fields/src/types/checkbox/index.ts +++ b/packages/fields/src/types/checkbox/index.ts @@ -7,6 +7,7 @@ import { legacyFilters, orderDirectionEnum, schema, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; @@ -30,6 +31,10 @@ export const checkbox = return fieldType({ kind: 'scalar', mode: 'optional', scalar: 'Boolean' })({ ...config, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].Boolean.optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: schema.Boolean }) }, update: { arg: schema.arg({ type: schema.Boolean }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, diff --git a/packages/fields/src/types/checkbox/views/index.tsx b/packages/fields/src/types/checkbox/views/index.tsx index 010f2f4a200..0b40d55766e 100644 --- a/packages/fields/src/types/checkbox/views/index.tsx +++ b/packages/fields/src/types/checkbox/views/index.tsx @@ -72,9 +72,8 @@ export const controller = (config: FieldControllerConfig): CheckboxController => Filter() { return null; }, - graphql({ type, value }) { - const key = type === 'is' ? `${config.path}` : `${config.path}_${type}`; - return { [key]: value }; + graphql({ type }) { + return { [config.path]: { equals: type === 'is' } }; }, Label({ label }) { return label.toLowerCase(); diff --git a/packages/fields/src/types/decimal/index.ts b/packages/fields/src/types/decimal/index.ts index a4b234cdda0..fdfdcaa1abf 100644 --- a/packages/fields/src/types/decimal/index.ts +++ b/packages/fields/src/types/decimal/index.ts @@ -8,6 +8,7 @@ import { Decimal, legacyFilters, FieldDefaultValue, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; import { getIndexType } from '../../get-index-type'; @@ -66,6 +67,10 @@ export const decimal = })({ ...config, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].Decimal.optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: schema.String }), resolve(val) { diff --git a/packages/fields/src/types/decimal/views/index.tsx b/packages/fields/src/types/decimal/views/index.tsx index 2d135af2d15..7e8b1cea9b8 100644 --- a/packages/fields/src/types/decimal/views/index.tsx +++ b/packages/fields/src/types/decimal/views/index.tsx @@ -70,14 +70,16 @@ export const controller = (config: Config): FieldController => { }, graphql: ({ type, value }) => { - const key = type === 'is' ? config.path : `${config.path}_${type}`; const valueWithoutWhitespace = value.replace(/\s/g, ''); - - return { - [key]: ['in', 'not_in'].includes(type) - ? valueWithoutWhitespace.split(',').map(i => i) - : valueWithoutWhitespace, - }; + const parsed = + type === 'in' || type === 'not_in' + ? valueWithoutWhitespace.split(',') + : valueWithoutWhitespace; + if (type === 'not') { + return { [config.path]: { not: { equals: parsed } } }; + } + const key = type === 'is' ? 'equals' : type === 'not_in' ? 'notIn' : type; + return { [config.path]: { [key]: parsed } }; }, Label({ label, value, type }) { let renderedValue = value; diff --git a/packages/fields/src/types/float/index.ts b/packages/fields/src/types/float/index.ts index c1baa891d85..a7522d3d017 100644 --- a/packages/fields/src/types/float/index.ts +++ b/packages/fields/src/types/float/index.ts @@ -7,6 +7,7 @@ import { orderDirectionEnum, legacyFilters, FieldDefaultValue, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; import { getIndexType } from '../../get-index-type'; @@ -36,6 +37,10 @@ export const float = })({ ...config, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].Float.optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: schema.Float }) }, update: { arg: schema.arg({ type: schema.Float }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, diff --git a/packages/fields/src/types/float/views/index.tsx b/packages/fields/src/types/float/views/index.tsx index 42c845075e1..8dd79257d11 100644 --- a/packages/fields/src/types/float/views/index.tsx +++ b/packages/fields/src/types/float/views/index.tsx @@ -68,14 +68,16 @@ export const controller = (config: FieldControllerConfig): FieldController { - const key = type === 'is' ? config.path : `${config.path}_${type}`; const valueWithoutWhitespace = value.replace(/\s/g, ''); - - return { - [key]: ['in', 'not_in'].includes(type) - ? valueWithoutWhitespace.split(',').map(i => parseFloat(i)) - : parseFloat(valueWithoutWhitespace), - }; + const parsed = + type === 'in' || type === 'not_in' + ? valueWithoutWhitespace.split(',').map(x => parseFloat(x)) + : parseFloat(valueWithoutWhitespace); + if (type === 'not') { + return { [config.path]: { not: { equals: parsed } } }; + } + const key = type === 'is' ? 'equals' : type === 'not_in' ? 'notIn' : type; + return { [config.path]: { [key]: parsed } }; }, Label({ label, value, type }) { let renderedValue = value; diff --git a/packages/fields/src/types/integer/index.ts b/packages/fields/src/types/integer/index.ts index 744bc9d849a..96c07d9af88 100644 --- a/packages/fields/src/types/integer/index.ts +++ b/packages/fields/src/types/integer/index.ts @@ -7,6 +7,7 @@ import { legacyFilters, orderDirectionEnum, schema, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; import { getIndexType } from '../../get-index-type'; @@ -37,6 +38,10 @@ export const integer = ...config, input: { uniqueWhere: isUnique ? { arg: schema.arg({ type: schema.Int }) } : undefined, + where: { + arg: schema.arg({ type: filters[meta.provider].Int.optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: schema.Int }) }, update: { arg: schema.arg({ type: schema.Int }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, diff --git a/packages/fields/src/types/integer/views/index.tsx b/packages/fields/src/types/integer/views/index.tsx index f05f3427065..c1de20b4f05 100644 --- a/packages/fields/src/types/integer/views/index.tsx +++ b/packages/fields/src/types/integer/views/index.tsx @@ -72,14 +72,16 @@ export const controller = (config: FieldControllerConfig): FieldController { - const key = type === 'is' ? config.path : `${config.path}_${type}`; const valueWithoutWhitespace = value.replace(/\s/g, ''); - - return { - [key]: ['in', 'not_in'].includes(type) - ? valueWithoutWhitespace.split(',').map(i => parseInt(i)) - : parseInt(valueWithoutWhitespace), - }; + const parsed = + type === 'in' || type === 'not_in' + ? valueWithoutWhitespace.split(',').map(x => parseInt(x)) + : parseInt(valueWithoutWhitespace); + if (type === 'not') { + return { [config.path]: { not: { equals: parsed } } }; + } + const key = type === 'is' ? 'equals' : type === 'not_in' ? 'notIn' : type; + return { [config.path]: { [key]: parsed } }; }, Label({ label, value, type }) { let renderedValue = value; diff --git a/packages/fields/src/types/password/index.ts b/packages/fields/src/types/password/index.ts index 3f3a10017d3..3bfbc35dc9e 100644 --- a/packages/fields/src/types/password/index.ts +++ b/packages/fields/src/types/password/index.ts @@ -34,6 +34,13 @@ const PasswordState = schema.object<{ isSet: boolean }>()({ }, }); +const PasswordFilter = schema.inputObject({ + name: 'PasswordFilter', + fields: { + isSet: schema.arg({ type: schema.nonNull(schema.Boolean) }), + }, +}); + const bcryptHashRegex = /^\$2[aby]?\$\d{1,2}\$[.\/A-Za-z0-9]{53}$/; export const password = @@ -89,6 +96,20 @@ export const password = })({ ...config, input: { + where: { + arg: schema.arg({ type: PasswordFilter }), + resolve(val) { + if (val === null) { + throw new Error('Password filters cannot be set to null'); + } + if (val.isSet) { + return { + not: null, + }; + } + return null; + }, + }, create: { arg: schema.arg({ type: schema.String }), resolve: inputResolver, diff --git a/packages/fields/src/types/password/views/index.tsx b/packages/fields/src/types/password/views/index.tsx index 0c1ecbfdb5a..7b8b29a3aad 100644 --- a/packages/fields/src/types/password/views/index.tsx +++ b/packages/fields/src/types/password/views/index.tsx @@ -200,8 +200,8 @@ export const controller = ( /> ); }, - graphql: ({ type, value }) => { - return { [`${config.path}_${type}`]: value }; + graphql: ({ value }) => { + return { [config.path]: { isSet: value } }; }, Label({ value }) { return value ? 'is set' : 'is not set'; diff --git a/packages/fields/src/types/relationship/index.ts b/packages/fields/src/types/relationship/index.ts index 65014067a40..6d937dcf8f1 100644 --- a/packages/fields/src/types/relationship/index.ts +++ b/packages/fields/src/types/relationship/index.ts @@ -153,6 +153,12 @@ export const relationship = })({ ...commonConfig, input: { + where: { + arg: schema.arg({ type: listTypes.relateTo.many.where }), + resolve(value, context, resolve) { + return resolve(value); + }, + }, create: { arg: schema.arg({ type: listTypes.relateTo.many.create, @@ -217,6 +223,12 @@ export const relationship = })({ ...commonConfig, input: { + where: { + arg: schema.arg({ type: listTypes.where }), + resolve(value, context, resolve) { + return resolve(value); + }, + }, create: { arg: schema.arg({ type: listTypes.relateTo.one.create }), async resolve(value, context, resolve) { diff --git a/packages/fields/src/types/relationship/tests/implementation.test.ts b/packages/fields/src/types/relationship/tests/implementation.test.ts index ea93d65957f..54de9fd8d69 100644 --- a/packages/fields/src/types/relationship/tests/implementation.test.ts +++ b/packages/fields/src/types/relationship/tests/implementation.test.ts @@ -123,7 +123,7 @@ describe('Type Generation', () => { expect(printType(schema.getType('Test')!)).toMatchInlineSnapshot(` "type Test { id: ID! - foo(where: ZipWhereInput! = {}, orderBy: [ZipOrderByInput!]! = [], first: Int, skip: Int! = 0): [Zip!] + foo(where: ZipWhereInput! = {}, orderBy: [ZipOrderByInput!]! = [], take: Int, skip: Int! = 0): [Zip!] fooCount(where: ZipWhereInput! = {}): Int }" `); @@ -135,7 +135,7 @@ describe('Type Generation', () => { expect(printType(schema.getType('Test')!)).toMatchInlineSnapshot(` "type Test { id: ID! - foo(where: ZipWhereInput! = {}, orderBy: [ZipOrderByInput!]! = [], first: Int, skip: Int! = 0): [Zip!] + foo(where: ZipWhereInput! = {}, orderBy: [ZipOrderByInput!]! = [], take: Int, skip: Int! = 0): [Zip!] }" `); }); diff --git a/packages/fields/src/types/relationship/views/RelationshipSelect.tsx b/packages/fields/src/types/relationship/views/RelationshipSelect.tsx index 44446e7bdd1..6f0a6980c26 100644 --- a/packages/fields/src/types/relationship/views/RelationshipSelect.tsx +++ b/packages/fields/src/types/relationship/views/RelationshipSelect.tsx @@ -105,10 +105,10 @@ export const RelationshipSelect = ({ const QUERY: TypedDocumentNode< { items: { [idField]: string; [labelField]: string | null }[]; count: number }, - { where: Record; first: number; skip: number } + { where: Record; take: number; skip: number } > = gql` - query RelationshipSelect($where: ${list.gqlNames.whereInputName}!, $first: Int!, $skip: Int!) { - items: ${list.gqlNames.listQueryName}(where: $where, first: $first, skip: $skip) { + query RelationshipSelect($where: ${list.gqlNames.whereInputName}!, $take: Int!, $skip: Int!) { + items: ${list.gqlNames.listQueryName}(where: $where, take: $take, skip: $skip) { ${idField}: id ${labelField}: ${list.labelField} ${extraSelection} @@ -121,7 +121,7 @@ export const RelationshipSelect = ({ const { data, error, loading, fetchMore } = useQuery(QUERY, { fetchPolicy: 'network-only', - variables: { where, first: initialItemsToLoad, skip: 0 }, + variables: { where, take: initialItemsToLoad, skip: 0 }, }); const count = data?.count || 0; @@ -146,10 +146,10 @@ export const RelationshipSelect = ({ if (!loading && isIntersecting && options.length < count) { const QUERY: TypedDocumentNode< { items: { [idField]: string; [labelField]: string | null }[] }, - { where: Record; first: number; skip: number } + { where: Record; take: number; skip: number } > = gql` - query RelationshipSelectMore($where: ${list.gqlNames.whereInputName}!, $first: Int!, $skip: Int!) { - items: ${list.gqlNames.listQueryName}(where: $where, first: $first, skip: $skip) { + query RelationshipSelectMore($where: ${list.gqlNames.whereInputName}!, $take: Int!, $skip: Int!) { + items: ${list.gqlNames.listQueryName}(where: $where, take: $take, skip: $skip) { ${labelField}: ${list.labelField} ${idField}: id ${extraSelection} @@ -160,7 +160,7 @@ export const RelationshipSelect = ({ query: QUERY, variables: { where, - first: subsequentItemsToLoad, + take: subsequentItemsToLoad, skip: data!.items.length, }, updateQuery: (prev, { fetchMoreResult }) => { diff --git a/packages/fields/src/types/select/index.ts b/packages/fields/src/types/select/index.ts index 78130da1f6b..8ec53f754e8 100644 --- a/packages/fields/src/types/select/index.ts +++ b/packages/fields/src/types/select/index.ts @@ -8,6 +8,7 @@ import { legacyFilters, orderDirectionEnum, schema, + filters, } from '@keystone-next/types'; // @ts-ignore import inflection from 'inflection'; @@ -68,6 +69,10 @@ export const select = })({ ...commonConfig, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].Int.optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: schema.Int }) }, update: { arg: schema.arg({ type: schema.Int }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, @@ -96,6 +101,10 @@ export const select = )({ ...commonConfig, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].enum(graphQLType).optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: graphQLType }) }, update: { arg: schema.arg({ type: graphQLType }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, @@ -109,6 +118,10 @@ export const select = return fieldType({ kind: 'scalar', scalar: 'String', mode: 'optional', index })({ ...commonConfig, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].String.optional }), + resolve: filters.resolveString, + }, create: { arg: schema.arg({ type: schema.String }) }, update: { arg: schema.arg({ type: schema.String }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, diff --git a/packages/fields/src/types/select/views/index.tsx b/packages/fields/src/types/select/views/index.tsx index 6fccd3a0bc0..ca3c939064f 100644 --- a/packages/fields/src/types/select/views/index.tsx +++ b/packages/fields/src/types/select/views/index.tsx @@ -116,31 +116,9 @@ export const controller = ( /> ); }, - - graphql: ({ type, value: options }) => { - const inverted = type === 'not_matches'; - - if (!options.length) { - return { - [`${config.path}${inverted ? '_not' : ''}`]: null, - }; - } - - const isMulti = options.length > 1; - - let key = config.path; - if (isMulti && inverted) { - key = `${config.path}_not_in`; - } else if (isMulti) { - key = `${config.path}_in`; - } else if (inverted) { - key = `${config.path}_not`; - } - - const value = isMulti ? options.map(x => t(x.value)) : t(options[0].value); - - return { [key]: value }; - }, + graphql: ({ type, value: options }) => ({ + [config.path]: { [type === 'not_matches' ? 'notIn' : 'in']: options.map(x => t(x.value)) }, + }), Label({ type, value }) { if (!value.length) { return type === 'not_matches' ? `is set` : `has no value`; diff --git a/packages/fields/src/types/text/index.ts b/packages/fields/src/types/text/index.ts index 8fe1e69f746..ecedaf0a5b4 100644 --- a/packages/fields/src/types/text/index.ts +++ b/packages/fields/src/types/text/index.ts @@ -7,6 +7,7 @@ import { orderDirectionEnum, FieldTypeFunc, legacyFilters, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; import { getIndexType } from '../../get-index-type'; @@ -40,6 +41,10 @@ export const text = ...config, input: { uniqueWhere: isUnique ? { arg: schema.arg({ type: schema.String }) } : undefined, + where: { + arg: schema.arg({ type: filters[meta.provider].String.optional }), + resolve: filters.resolveString, + }, create: { arg: schema.arg({ type: schema.String }) }, update: { arg: schema.arg({ type: schema.String }) }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, @@ -47,7 +52,10 @@ export const text = output: schema.field({ type: schema.String }), views: resolveView('text/views'), getAdminMeta() { - return { displayMode: config.ui?.displayMode ?? 'input' }; + return { + displayMode: config.ui?.displayMode ?? 'input', + shouldUseModeInsensitive: meta.provider === 'postgresql', + }; }, __legacy: { filters: { diff --git a/packages/fields/src/types/text/views/index.tsx b/packages/fields/src/types/text/views/index.tsx index c9fd5cc0245..1405b86df73 100644 --- a/packages/fields/src/types/text/views/index.tsx +++ b/packages/fields/src/types/text/views/index.tsx @@ -50,7 +50,10 @@ export const CardValue: CardValueComponent = ({ item, field }) => { ); }; -type Config = FieldControllerConfig<{ displayMode: 'input' | 'textarea' }>; +type Config = FieldControllerConfig<{ + displayMode: 'input' | 'textarea'; + shouldUseModeInsensitive: boolean; +}>; export const controller = ( config: Config @@ -80,13 +83,25 @@ export const controller = ( }, graphql: ({ type, value }) => { - const key = type === 'is_i' ? `${config.path}_i` : `${config.path}_${type}`; - return { [key]: value }; + const isNot = type.startsWith('not_'); + const key = + type === 'is_i' || type === 'not_i' + ? 'equals' + : type + .replace(/_i$/, '') + .replace('not_', '') + .replace(/_([a-z])/g, (_, char: string) => char.toUpperCase()); + const filter = { [key]: value }; + return { + [config.path]: { + ...(isNot ? { not: filter } : filter), + mode: config.fieldMeta.shouldUseModeInsensitive ? 'insensitive' : undefined, + }, + }; }, Label({ label, value }) { return `${label.toLowerCase()}: "${value}"`; }, - // FIXME: Not all of these options will work with prisma_sqlite types: { contains_i: { label: 'Contains', diff --git a/packages/fields/src/types/timestamp/index.ts b/packages/fields/src/types/timestamp/index.ts index 81df675377d..b5203d908ab 100644 --- a/packages/fields/src/types/timestamp/index.ts +++ b/packages/fields/src/types/timestamp/index.ts @@ -7,6 +7,7 @@ import { orderDirectionEnum, legacyFilters, FieldDefaultValue, + filters, } from '@keystone-next/types'; import { resolveView } from '../../resolve-view'; import { getIndexType } from '../../get-index-type'; @@ -42,6 +43,10 @@ export const timestamp = })({ ...config, input: { + where: { + arg: schema.arg({ type: filters[meta.provider].DateTime.optional }), + resolve: filters.resolveCommon, + }, create: { arg: schema.arg({ type: schema.String }), resolve: inputResolver }, update: { arg: schema.arg({ type: schema.String }), resolve: inputResolver }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, diff --git a/packages/keystone/CHANGELOG.md b/packages/keystone/CHANGELOG.md index eb2919d6459..718e85be1cd 100644 --- a/packages/keystone/CHANGELOG.md +++ b/packages/keystone/CHANGELOG.md @@ -1,5 +1,170 @@ # @keystone-next/keystone +## 24.0.0 + +### Major Changes + +- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `_ListKeyMeta` and `_toManyRelationshipFieldMeta` fields. You should use `listKeyCount` and `toManyRelationshipFieldCount` instead + +* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed all arguments from `context.lists.List.count` and `context.db.lists.List.count` except for `where`. + +- [#6266](https://github.com/keystonejs/keystone/pull/6266) [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Renamed `first` argument in find many queries to `take` to align with Prisma. + + ```graphql + type Query { + users( + where: UserWhereInput! = {} + orderBy: [UserOrderByInput!]! = [] + # previously was first: Int + take: Int + skip: Int! = 0 + ): [User!] + # ... + } + + type User { + # ... + posts( + where: PostWhereInput! = {} + orderBy: [PostOrderByInput!]! = [] + # previously was first: Int + take: Int + skip: Int! = 0 + ): [Post!] + # ... + } + ``` + +* [#6208](https://github.com/keystonejs/keystone/pull/6208) [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The create one mutation now requires a non-null `data` argument and the create many mutation accepts a list of `ItemCreateInput` directly instead of being nested inside of an object with the `ItemCreateInput` in a `data` field. + + If you have a list called `Item`, `createItem` now looks like `createItem(data: ItemCreateInput!): Item` and `createItems` now looks like `createItems(data: [ItemCreateInput!]!): [Item]`. + +- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `search` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `contains` filters instead. + +* [#6095](https://github.com/keystonejs/keystone/pull/6095) [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information. + + ```graphql + query { + posts(where: { title: { contains: "Something" } }) { + title + content + } + } + ``` + +- [#6198](https://github.com/keystonejs/keystone/pull/6198) [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b) Thanks [@timleslie](https://github.com/timleslie)! - Removed the `uid` and `name` properties from the errors returned by the GraphQL API. + +* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `sortBy` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `orderBy` instead. + +- [#6312](https://github.com/keystonejs/keystone/pull/6312) [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated `@graphql-ts/schema`. The second type parameter of `schema.Arg` exported from `@keystone-next/types` is now a boolean that defines whether or not the arg has a default value to make it easier to define circular input objects. + +* [#6217](https://github.com/keystonejs/keystone/pull/6217) [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been renamed to `disconnect` in to-one relationship inputs and the old `disconnect` field has been removed. There are also seperate input types for create and update where the input for create doesn't have `disconnect`. It's also now required that if you provide a to-one relationship input, you must provide exactly one field to the input. + + If you have a list called `Item`, the to-one relationship inputs now look like this: + + ```graphql + input ItemRelateToOneForCreateInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + } + input ItemRelateToOneForUpdateInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + disconnect: Boolean + } + ``` + +- [#6224](https://github.com/keystonejs/keystone/pull/6224) [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been replaced by `set` in to-many relationship inputs, the equivalent to `disconnectAll: true` is now `set: []`. There are also seperate input types for create and update where the input for create doesn't have `disconnect` or `set`. The inputs in the lists in the input field are now also non-null. + + If you have a list called `Item`, the to-many relationship inputs now look like this: + + ```graphql + input ItemRelateToManyForCreateInput { + create: [ItemCreateInput!] + connect: [ItemWhereUniqueInput!] + } + input ItemRelateToManyForUpdateInput { + disconnect: [ItemWhereUniqueInput!] + set: [ItemWhereUniqueInput!] + create: [ItemCreateInput!] + connect: [ItemWhereUniqueInput!] + } + ``` + +* [#6197](https://github.com/keystonejs/keystone/pull/6197) [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. + + If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. + + Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. + +- [#6211](https://github.com/keystonejs/keystone/pull/6211) [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. + + If you have a list called `Item`, the update mutations now look like this: + + ```graphql + type Mutation { + updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item + updateItems(data: [ItemUpdateArgs!]!): [Item] + } + + input ItemUpdateArgs { + where: ItemWhereUniqueInput! + data: ItemUpdateInput! + } + ``` + +* [#6206](https://github.com/keystonejs/keystone/pull/6206) [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The delete mutations now accept `where` unique inputs instead of only an `id`. + + If you have a list called `Item`, `deleteItem` now looks like `deleteItem(where: ItemWhereUniqueInput!): Item` and `deleteItems` now looks like `deleteItems(where: [ItemWhereUniqueInput!]!): [Item]` + +### Minor Changes + +- [#6276](https://github.com/keystonejs/keystone/pull/6276) [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb) Thanks [@gautamsi](https://github.com/gautamsi)! - Added option for `Bearer` token auth when using session. + +* [#6267](https://github.com/keystonejs/keystone/pull/6267) [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590) Thanks [@timleslie](https://github.com/timleslie)! - Added `config.graphql.debug` option, which can be used to control whether debug information such as stack traces are included in the errors returned by the GraphQL API. + +### Patch Changes + +- [#6317](https://github.com/keystonejs/keystone/pull/6317) [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18) Thanks [@timleslie](https://github.com/timleslie)! - Separated the resolving of non-relationship field from relationship fields in create/update inputs to allow for better error handling. + +* [#6250](https://github.com/keystonejs/keystone/pull/6250) [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450) Thanks [@timleslie](https://github.com/timleslie)! - Updated internal type definitions. + +- [#6334](https://github.com/keystonejs/keystone/pull/6334) [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Resolved bug with visually hidden elements in ListView checkboxes expanding to fill the whole body on click of elements near the bottom of the screen. + +* [#6219](https://github.com/keystonejs/keystone/pull/6219) [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused code path in Admin UI error display. + +- [#6269](https://github.com/keystonejs/keystone/pull/6269) [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Added ignoreBuildErrors flag to next-config.js file, to negate false positive errors in keystone builds with imported components. + +* [#6218](https://github.com/keystonejs/keystone/pull/6218) [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2) Thanks [@timleslie](https://github.com/timleslie)! - Added more details to validation failure error messages. + +- [#6316](https://github.com/keystonejs/keystone/pull/6316) [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4) Thanks [@timleslie](https://github.com/timleslie)! - Updated handling of errors in `resolveInput` hooks to provide developers with appropriate debug information. + +* [#6310](https://github.com/keystonejs/keystone/pull/6310) [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053) Thanks [@timleslie](https://github.com/timleslie)! - Updated dependencies to use `mergeSchemas` from `@graphql-tools/schema`, rather than its old location in `@graphql-tools/merge`. You might see a reordering of the contents of your `graphql.schema` file. + +- [#6292](https://github.com/keystonejs/keystone/pull/6292) [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3) Thanks [@renovate](https://github.com/apps/renovate)! - Updated Prisma dependencies to `2.29.1`. + +* [#6263](https://github.com/keystonejs/keystone/pull/6263) [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524) Thanks [@timleslie](https://github.com/timleslie)! - Made the original stacktraces for before/after hooks available on `error.extension.errors`. + +- [#6259](https://github.com/keystonejs/keystone/pull/6259) [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Bumped @apollo/client dependency to ^3.4.5, the update resolves the following useQuery [issue](https://github.com/keystonejs/keystone/issues/6254). + +* [#6239](https://github.com/keystonejs/keystone/pull/6239) [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae) Thanks [@timleslie](https://github.com/timleslie)! - Added more details to before/after change/delete hook error messages. + +- [#6248](https://github.com/keystonejs/keystone/pull/6248) [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused dependency `@graphql-tools/schema`. + +* [#6203](https://github.com/keystonejs/keystone/pull/6203) [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3) Thanks [@renovate](https://github.com/apps/renovate)! - Updated Prisma dependencies to `2.28.0`. + +- [#6296](https://github.com/keystonejs/keystone/pull/6296) [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed delete success notifications in the Admin UI appearing on failed deletes in List view and Item view. + +* [#6200](https://github.com/keystonejs/keystone/pull/6200) [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e) Thanks [@timleslie](https://github.com/timleslie)! - Updated internal error handling to use the `apollo-server-errors` package instead of `apollo-errors`. + +* Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`c2bb6a9a5`](https://github.com/keystonejs/keystone/commit/c2bb6a9a596fc52a3c61ec5d91c79758e417e61d), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/types@24.0.0 + - @keystone-ui/notice@4.0.1 + - @keystone-ui/toast@4.0.2 + - @keystone-next/admin-ui-utils@5.0.6 + - @keystone-next/utils@1.0.4 + ## 23.0.3 ### Patch Changes diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 5c70c4c0abc..d2be3d4829e 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/keystone", - "version": "23.0.3", + "version": "24.0.0", "license": "MIT", "main": "dist/keystone.cjs.js", "module": "dist/keystone.esm.js", @@ -22,33 +22,33 @@ "keystone-next": "bin/cli.js" }, "dependencies": { - "@apollo/client": "3.3.21", - "@babel/core": "^7.14.8", - "@babel/plugin-transform-modules-commonjs": "^7.14.5", - "@babel/runtime": "^7.14.8", + "@apollo/client": "^3.4.8", + "@babel/core": "^7.15.0", + "@babel/plugin-transform-modules-commonjs": "^7.15.0", + "@babel/runtime": "^7.15.3", "@emotion/hash": "^0.8.0", - "@graphql-tools/merge": "^6.2.16", + "@graphql-tools/schema": "^8.1.1", "@hapi/iron": "^6.0.0", - "@keystone-next/admin-ui-utils": "^5.0.5", - "@keystone-next/fields": "^13.0.0", - "@keystone-next/types": "^23.0.0", - "@keystone-next/utils": "^1.0.3", + "@keystone-next/admin-ui-utils": "^5.0.6", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/types": "^24.0.0", + "@keystone-next/utils": "^1.0.4", "@keystone-ui/button": "^5.0.0", "@keystone-ui/core": "^3.1.1", "@keystone-ui/fields": "^4.1.2", "@keystone-ui/icons": "^4.0.0", "@keystone-ui/loading": "^4.0.0", "@keystone-ui/modals": "^4.0.0", - "@keystone-ui/notice": "^4.0.0", + "@keystone-ui/notice": "^4.0.1", "@keystone-ui/options": "^4.0.1", "@keystone-ui/pill": "^5.0.0", "@keystone-ui/popover": "^4.0.2", - "@keystone-ui/toast": "^4.0.1", + "@keystone-ui/toast": "^4.0.2", "@keystone-ui/tooltip": "^4.0.1", "@preconstruct/next": "^3.0.0", - "@prisma/client": "2.28.0", - "@prisma/migrate": "2.28.0", - "@prisma/sdk": "2.28.0", + "@prisma/client": "2.29.1", + "@prisma/migrate": "2.29.1", + "@prisma/sdk": "2.29.1", "@sindresorhus/slugify": "^1.1.2", "@types/apollo-upload-client": "14.1.0", "@types/babel__core": "^7.1.15", @@ -94,7 +94,7 @@ "pirates": "^4.0.1", "pluralize": "^8.0.0", "prettier": "^2.3.2", - "prisma": "2.28.0", + "prisma": "2.29.1", "prompts": "^2.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx index 53d48f340f5..cba2c258087 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx @@ -53,13 +53,18 @@ export const controller = ( }, graphql: ({ type, value }) => { - const key = type === 'is' ? config.path : `${config.path}_${type}`; + if (type === 'not') { + return { [config.path]: { not: { equals: value } } }; + } const valueWithoutWhitespace = value.replace(/\s/g, ''); + const key = type === 'is' ? 'equals' : type === 'not_in' ? 'notIn' : type; return { - [key]: ['in', 'not_in'].includes(type) - ? valueWithoutWhitespace.split(',') - : valueWithoutWhitespace, + [config.path]: { + [key]: ['in', 'not_in'].includes(type) + ? valueWithoutWhitespace.split(',') + : valueWithoutWhitespace, + }, }; }, Label({ label, value, type }) { diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts index e7c0984a39f..db51999f8e2 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts @@ -3,6 +3,9 @@ import Path from 'path'; import withPreconstruct from '@preconstruct/next'; export const config = withPreconstruct({ + typescript: { + ignoreBuildErrors: true, + }, webpack(config: any, { isServer }: any) { config.resolve.alias = { ...config.resolve.alias, diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx index 5ea383f38be..a49288a34c7 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx @@ -253,17 +253,19 @@ function DeleteButton({ confirm: { label: 'Delete', action: async () => { - await deleteItem().catch(err => { - toasts.addToast({ - title: 'Failed to delete item', + try { + await deleteItem(); + } catch (err) { + return toasts.addToast({ + title: `Failed to delete ${list.singular} item: ${itemLabel}`, message: err.message, tone: 'negative', }); - }); + } router.push(`/${list.path}`); - toasts.addToast({ + return toasts.addToast({ title: itemLabel, - message: 'Deleted successfully', + message: `Deleted ${list.singular} item successfully`, tone: 'positive', }); }, diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx index e3b977c8737..a3f1e6203ca 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx @@ -176,12 +176,12 @@ const ListPage = ({ listKey }: ListPageProps) => { }) .join('\n'); return gql` - query ($where: ${list.gqlNames.whereInputName}, $first: Int!, $skip: Int!, $orderBy: [${ + query ($where: ${list.gqlNames.whereInputName}, $take: Int!, $skip: Int!, $orderBy: [${ list.gqlNames.listOrderName }!]) { items: ${ list.gqlNames.listQueryName - }(where: $where,first: $first, 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' @@ -197,7 +197,7 @@ const ListPage = ({ listKey }: ListPageProps) => { errorPolicy: 'all', variables: { where: filters.where, - first: pageSize, + take: pageSize, skip: (currentPage - 1) * pageSize, orderBy: sort ? [{ [sort.field]: sort.direction.toLowerCase() }] : undefined, }, @@ -244,7 +244,6 @@ const ListPage = ({ listKey }: ListPageProps) => { const theme = useTheme(); const showCreate = !(metaQuery.data?.keystone.adminMeta.list?.hideCreate ?? true) || null; - return ( }> {metaQuery.error ? ( @@ -436,14 +435,18 @@ function DeleteManyButton({ useMemo( () => gql` - mutation($where: [${list.gqlNames.whereUniqueInputName}!]!) { - ${list.gqlNames.deleteManyMutationName}(where: $where) { - id - } - } + mutation($where: [${list.gqlNames.whereUniqueInputName}!]!) { + ${list.gqlNames.deleteManyMutationName}(where: $where) { + id + ${list.labelField} + } + } `, [list] - ) + ), + { + errorPolicy: 'all', + } ); const [isOpen, setIsOpen] = useState(false); const toasts = useToasts(); @@ -467,20 +470,75 @@ function DeleteManyButton({ confirm: { label: 'Delete', action: async () => { - await deleteItems({ + const { data, errors } = await deleteItems({ variables: { where: [...selectedItems].map(id => ({ id })) }, - }).catch(err => { + }); + /* + Data returns an array where successful deletions are item objects + and unsuccessful deletions are null values. + Run a reduce to count success and failure as well as + to generate the success message to be passed to the success toast + */ + const { successfulItems, unsuccessfulItems, successMessage } = data[ + list.gqlNames.deleteManyMutationName + ].reduce( + ( + acc: { + successfulItems: number; + unsuccessfulItems: number; + successMessage: string; + }, + curr: any + ) => { + if (curr) { + acc.successfulItems++; + acc.successMessage = + acc.successMessage === '' + ? (acc.successMessage += curr.label) + : (acc.successMessage += `, ${curr.label}`); + } else { + acc.unsuccessfulItems++; + } + return acc; + }, + { successfulItems: 0, unsuccessfulItems: 0, successMessage: '' } as { + successfulItems: number; + unsuccessfulItems: number; + successMessage: string; + } + ); + + // If there are errors + if (errors?.length) { + // Find out how many items failed to delete. + // Reduce error messages down to unique instances, and append to the toast as a message. toasts.addToast({ - title: 'Failed to delete items', - message: err.message, tone: 'negative', + title: `Failed to delete ${unsuccessfulItems} of ${ + data[list.gqlNames.deleteManyMutationName].length + } ${list.plural}`, + message: errors + .reduce((acc, error) => { + if (acc.indexOf(error.message) < 0) { + acc.push(error.message); + } + return acc; + }, [] as string[]) + .join('\n'), }); - }); - toasts.addToast({ - title: 'Deleted items successfully', - tone: 'positive', - }); - refetch(); + } + + if (successfulItems) { + toasts.addToast({ + tone: 'positive', + title: `Deleted ${successfulItems} of ${ + data[list.gqlNames.deleteManyMutationName].length + } ${list.plural} successfully`, + message: successMessage, + }); + } + + return refetch(); }, }, cancel: { @@ -523,7 +581,6 @@ function ListTable({ const { query } = useRouter(); const shouldShowLinkIcon = !list.fields[selectedFields.keys().next().value].views.Cell.supportsLinkTo; - return ( @@ -614,7 +671,7 @@ function ListTable({ minHeight: 38, alignItems: 'center', justifyContent: 'start', - // cursor: 'pointer', + position: 'relative', }} > ) => { padding: spacing.small, textAlign: 'left', position: 'sticky', + zIndex: 1, top: 0, }} {...props} diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts index 0a032bfe62b..78ec432b4c4 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts @@ -15,7 +15,7 @@ export function nextGraphQLAPIRoute(keystoneConfig: KeystoneConfig, prismaClient graphQLSchema, createContext: keystone.createContext, sessionStrategy: initializedKeystoneConfig.session, - apolloConfig: initializedKeystoneConfig.graphql?.apolloConfig, + graphqlConfig: initializedKeystoneConfig.graphql, connectionPromise: keystone.connect(), }); diff --git a/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts b/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts index fcc65b63eda..29bf7753c32 100644 --- a/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts +++ b/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts @@ -1,4 +1,4 @@ -import { JSONValue, schema as schemaAPIFromTypesPkg } from '@keystone-next/types'; +import { JSONValue, QueryMode, schema as schemaAPIFromTypesPkg } from '@keystone-next/types'; import { KeystoneContext, KeystoneConfig, @@ -6,7 +6,7 @@ import { ListMetaRootVal, FieldMetaRootVal, } from '@keystone-next/types'; -import { GraphQLSchema, GraphQLObjectType, assertScalarType } from 'graphql'; +import { GraphQLSchema, GraphQLObjectType, assertScalarType, assertEnumType } from 'graphql'; import { InitialisedList } from '../../lib/core/types-for-lists'; const schema = { @@ -35,6 +35,10 @@ export function getAdminMetaSchema({ const jsonScalar = jsonScalarType ? schema.scalar(assertScalarType(jsonScalarType)) : schemaAPIFromTypesPkg.JSON; + const queryModeEnumType = graphQLSchema.getType('QueryMode'); + const queryModeEnum = queryModeEnumType + ? { ...QueryMode, graphQLType: assertEnumType(graphQLSchema.getType('QueryMode')) } + : QueryMode; const KeystoneAdminUIFieldMeta = schema.object()({ name: 'KeystoneAdminUIFieldMeta', @@ -153,10 +157,7 @@ export function getAdminMetaSchema({ }), }), search: schema.field({ - type: schema.enum({ - name: 'QueryMode', - values: schema.enumValues(['default', 'insensitive']), - }), + type: queryModeEnum, }), }, }); diff --git a/packages/keystone/src/admin-ui/templates/api.ts b/packages/keystone/src/admin-ui/templates/api.ts index 01d75117313..c779651e582 100644 --- a/packages/keystone/src/admin-ui/templates/api.ts +++ b/packages/keystone/src/admin-ui/templates/api.ts @@ -9,7 +9,7 @@ const apolloServer = createApolloServerMicro({ graphQLSchema, createContext, sessionStrategy: initializedKeystoneConfig.session ? initializedKeystoneConfig.session() : undefined, - apolloConfig: initializedKeystoneConfig.graphql?.apolloConfig, + graphqlConfig: initializedKeystoneConfig.graphql, connectionPromise: keystone.connect(), }); diff --git a/packages/keystone/src/lib/core/graphql-errors.ts b/packages/keystone/src/lib/core/graphql-errors.ts index cb760fd554d..6587864b984 100644 --- a/packages/keystone/src/lib/core/graphql-errors.ts +++ b/packages/keystone/src/lib/core/graphql-errors.ts @@ -7,9 +7,14 @@ export const validationFailureError = (messages: string[]) => { return new ApolloError(`You provided invalid data for this operation.\n${s}`); }; -export const extensionError = (extension: string, messages: string[]) => { - const s = messages.map(m => ` - ${m}`).join('\n'); - return new ApolloError(`An error occured while running "${extension}".\n${s}`); +export const extensionError = (extension: string, things: { error: Error; tag: string }[]) => { + const s = things.map(t => ` - ${t.tag}: ${t.error.message}`).join('\n'); + return new ApolloError( + `An error occured while running "${extension}".\n${s}`, + 'INTERNAL_SERVER_ERROR', + // Make the original stack traces available. + { debug: things.map(t => ({ stacktrace: t.error.stack, message: t.error.message })) } + ); }; // FIXME: In an upcoming PR we will use these args to construct a better diff --git a/packages/keystone/src/lib/core/mutations/access-control.ts b/packages/keystone/src/lib/core/mutations/access-control.ts index 51efe776857..0756a934f12 100644 --- a/packages/keystone/src/lib/core/mutations/access-control.ts +++ b/packages/keystone/src/lib/core/mutations/access-control.ts @@ -35,7 +35,7 @@ export async function getAccessControlledItemForDelete( // List access: pass 2 let where: PrismaFilter = mapUniqueWhereToWhere(list, uniqueWhere); if (typeof access === 'object') { - where = { AND: [where, await resolveWhereInput(access, list)] }; + where = { AND: [where, await resolveWhereInput(access, list, context)] }; } const item = await runWithPrisma(context, list, model => model.findFirst({ where })); if (item === null) { @@ -78,7 +78,9 @@ export async function getAccessControlledItemForUpdate( where: accessControl === true ? uniqueWhereInWhereForm - : { AND: [uniqueWhereInWhereForm, await resolveWhereInput(accessControl, list)] }, + : { + AND: [uniqueWhereInWhereForm, await resolveWhereInput(accessControl, list, context)], + }, }) ); if (!item) { diff --git a/packages/keystone/src/lib/core/mutations/create-update.ts b/packages/keystone/src/lib/core/mutations/create-update.ts index eda831a0393..289d34a9821 100644 --- a/packages/keystone/src/lib/core/mutations/create-update.ts +++ b/packages/keystone/src/lib/core/mutations/create-update.ts @@ -9,6 +9,7 @@ import { runWithPrisma, } from '../utils'; import { resolveUniqueWhereInput, UniqueInputFilter } from '../where-inputs'; +import { extensionError } from '../graphql-errors'; import { resolveRelateToManyForCreateInput, resolveRelateToManyForUpdateInput, @@ -179,21 +180,32 @@ async function getResolvedData( ); } - // Apply field type input resolvers + // Apply non-relationship field type input resolvers resolvedData = Object.fromEntries( await promiseAllRejectWithAllErrors( Object.entries(list.fields).map(async ([fieldKey, field]) => { const inputResolver = field.input?.[operation]?.resolve; let input = resolvedData[fieldKey]; - if (inputResolver) { + if (inputResolver && field.dbField.kind !== 'relation') { + input = await inputResolver(input, context, undefined); + } + return [fieldKey, input] as const; + }) + ) + ); + + // Apply relationship field type input resolvers + resolvedData = Object.fromEntries( + await promiseAllRejectWithAllErrors( + Object.entries(list.fields).map(async ([fieldKey, field]) => { + const inputResolver = field.input?.[operation]?.resolve; + let input = resolvedData[fieldKey]; + if (inputResolver && field.dbField.kind === 'relation') { input = await inputResolver( input, context, + // This third argument only applies to relationship fields (() => { - // This third argument only applies to relationship fields - if (field.dbField.kind !== 'relation') { - return undefined; - } if (input === undefined) { // No-op: This is what we want return () => undefined; @@ -228,23 +240,37 @@ async function getResolvedData( ); // Resolve input hooks - resolvedData = Object.fromEntries( - await promiseAllRejectWithAllErrors( - Object.entries(list.fields).map(async ([fieldKey, field]) => { - if (field.hooks.resolveInput === undefined) { - return [fieldKey, resolvedData[fieldKey]]; - } - const value = await field.hooks.resolveInput({ + const hookName = 'resolveInput'; + // Field hooks + let _resolvedData: Record = {}; + const fieldsErrors: { error: Error; tag: string }[] = []; + for (const [fieldPath, field] of Object.entries(list.fields)) { + if (field.hooks.resolveInput === undefined) { + _resolvedData[fieldPath] = resolvedData[fieldPath]; + } else { + try { + _resolvedData[fieldPath] = await field.hooks.resolveInput({ ...hookArgs, resolvedData, - fieldPath: fieldKey, + fieldPath, }); - return [fieldKey, value]; - }) - ) - ); + } catch (error) { + fieldsErrors.push({ error, tag: `${list.listKey}.${fieldPath}` }); + } + } + } + if (fieldsErrors.length) { + throw extensionError(hookName, fieldsErrors); + } + resolvedData = _resolvedData; + + // List hooks if (list.hooks.resolveInput) { - resolvedData = (await list.hooks.resolveInput({ ...hookArgs, resolvedData })) as any; + try { + resolvedData = (await list.hooks.resolveInput({ ...hookArgs, resolvedData })) as any; + } catch (error) { + throw extensionError(hookName, [{ error, tag: list.listKey }]); + } } return resolvedData; diff --git a/packages/keystone/src/lib/core/mutations/hooks.ts b/packages/keystone/src/lib/core/mutations/hooks.ts index 38cff0a8d7c..eeac512823f 100644 --- a/packages/keystone/src/lib/core/mutations/hooks.ts +++ b/packages/keystone/src/lib/core/mutations/hooks.ts @@ -31,14 +31,13 @@ export async function runSideEffectOnlyHook< } // Field hooks - const fieldsErrors = []; + const fieldsErrors: { error: Error; tag: string }[] = []; for (const [fieldPath, field] of Object.entries(list.fields)) { if (shouldRunFieldLevelHook(fieldPath)) { try { - // @ts-ignore await field.hooks[hookName]?.({ fieldPath, ...args }); - } catch (err) { - fieldsErrors.push(`${list.listKey}.${fieldPath}: ${err.message}`); + } catch (error) { + fieldsErrors.push({ error, tag: `${list.listKey}.${fieldPath}` }); } } } @@ -49,7 +48,7 @@ export async function runSideEffectOnlyHook< // List hooks try { await list.hooks[hookName]?.(args); - } catch (err) { - throw extensionError(hookName, [`${list.listKey}: ${err.message}`]); + } catch (error) { + throw extensionError(hookName, [{ error, tag: list.listKey }]); } } diff --git a/packages/keystone/src/lib/core/queries/resolvers.ts b/packages/keystone/src/lib/core/queries/resolvers.ts index 35e421b4e26..21a9225146c 100644 --- a/packages/keystone/src/lib/core/queries/resolvers.ts +++ b/packages/keystone/src/lib/core/queries/resolvers.ts @@ -59,7 +59,7 @@ export async function accessControlledFilter( // Merge declarative access control if (typeof access === 'object') { - resolvedWhere = { AND: [resolvedWhere, await resolveWhereInput(access, list)] }; + resolvedWhere = { AND: [resolvedWhere, await resolveWhereInput(access, list, context)] }; } return resolvedWhere; @@ -86,7 +86,7 @@ export async function findOne( } export async function findMany( - { where, first, skip, orderBy: rawOrderBy }: FindManyArgsValue, + { where, take, skip, orderBy: rawOrderBy }: FindManyArgsValue, list: InitialisedList, context: KeystoneContext, info: GraphQLResolveInfo, @@ -94,16 +94,16 @@ export async function findMany( ): Promise { const orderBy = await resolveOrderBy(rawOrderBy, list, context); - applyEarlyMaxResults(first, list); + applyEarlyMaxResults(take, list); - let resolvedWhere = await resolveWhereInput(where || {}, list); + let resolvedWhere = await resolveWhereInput(where, list, context); resolvedWhere = await accessControlledFilter(list, context, resolvedWhere); const results = await runWithPrisma(context, list, model => model.findMany({ where: extraFilter === undefined ? resolvedWhere : { AND: [resolvedWhere, extraFilter] }, orderBy, - take: first ?? undefined, + take: take ?? undefined, skip, }) ); @@ -166,7 +166,7 @@ export async function count( info: GraphQLResolveInfo, extraFilter?: PrismaFilter ) { - let resolvedWhere = await resolveWhereInput(where || {}, list); + let resolvedWhere = await resolveWhereInput(where, list, context); resolvedWhere = await accessControlledFilter(list, context, resolvedWhere); const count = await runWithPrisma(context, list, model => @@ -186,16 +186,16 @@ export async function count( return count; } -function applyEarlyMaxResults(_first: number | null | undefined, list: InitialisedList) { - const first = _first ?? Infinity; +function applyEarlyMaxResults(_take: number | null | undefined, list: InitialisedList) { + const take = _take ?? Infinity; // We want to help devs by failing fast and noisily if limits are violated. // Unfortunately, we can't always be sure of intent. - // E.g., if the query has a "first: 10", is it bad if more results could come back? + // E.g., if the query has a "take: 10", is it bad if more results could come back? // Maybe yes, or maybe the dev is just paginating posts. // But we can be sure there's a problem in two cases: - // * The query explicitly has a "first" that exceeds the limit - // * The query has no "first", and has more results than the limit - if (first < Infinity && first > list.maxResults) { + // * The query explicitly has a "take" that exceeds the limit + // * The query has no "take", and has more results than the limit + if (take < Infinity && take > list.maxResults) { throw limitsExceededError({ list: list.listKey, type: 'maxResults', limit: list.maxResults }); } } diff --git a/packages/keystone/src/lib/core/types-for-lists.ts b/packages/keystone/src/lib/core/types-for-lists.ts index 18ab3c6b78d..d4408407ebc 100644 --- a/packages/keystone/src/lib/core/types-for-lists.ts +++ b/packages/keystone/src/lib/core/types-for-lists.ts @@ -22,7 +22,6 @@ import { } from './access-control'; import { getNamesFromList } from './utils'; import { ResolvedDBField, resolveRelationships } from './resolve-relationships'; -import { InputFilter, PrismaFilter, resolveWhereInput } from './where-inputs'; import { outputTypeField } from './queries/output-field'; import { assertFieldsValid } from './field-assertions'; @@ -37,7 +36,6 @@ export type InitialisedList = { /** This will include the opposites to one-sided relationships */ resolvedDbFields: Record; pluralGraphQLName: string; - filterImpls: Record PrismaFilter>; types: TypesForList; access: ResolvedListAccessControl; hooks: ListHooks; @@ -111,9 +109,12 @@ export function initialiseLists( { AND: schema.arg({ type: schema.list(schema.nonNull(where)) }), OR: schema.arg({ type: schema.list(schema.nonNull(where)) }), + NOT: schema.arg({ type: schema.list(schema.nonNull(where)) }), }, - ...Object.values(fields).map(field => - field.access.read === false ? {} : field.__legacy?.filters?.fields ?? {} + ...Object.entries(fields).map( + ([fieldKey, field]) => + field.input?.where?.arg && + field.access.read !== false && { [fieldKey]: field.input?.where?.arg } ) ); }, @@ -165,7 +166,7 @@ export function initialiseLists( defaultValue: [], }), // TODO: non-nullable when max results is specified in the list with the default of max results - first: schema.arg({ type: schema.Int }), + take: schema.arg({ type: schema.Int }), skip: schema.arg({ type: schema.nonNull(schema.Int), defaultValue: 0 }), }; @@ -234,7 +235,18 @@ export function initialiseLists( update, findManyArgs, relateTo: { - many: { create: relateToManyForCreate, update: relateToManyForUpdate }, + many: { + where: schema.inputObject({ + name: `${listKey}ManyRelationFilter`, + fields: { + every: schema.arg({ type: where }), + some: schema.arg({ type: where }), + none: schema.arg({ type: where }), + }, + }), + create: relateToManyForCreate, + update: relateToManyForUpdate, + }, one: { create: relateToOneForCreate, update: relateToOneForUpdate }, }, }, @@ -304,27 +316,6 @@ export function initialiseLists( ...listInfos[listKey], ...listsWithResolvedDBFields[listKey], hooks: list.hooks || {}, - filterImpls: Object.assign( - {}, - ...Object.values(list.fields).map(field => { - if (field.dbField.kind === 'relation' && field.__legacy?.filters) { - const foreignListKey = field.dbField.list; - return Object.fromEntries( - Object.entries(field.__legacy.filters.impls).map(([key, resolve]) => { - return [ - key, - (val: any) => - resolve(val, foreignListWhereInput => - resolveWhereInput(foreignListWhereInput, lists[foreignListKey]) - ), - ]; - }) - ); - } else { - return field.__legacy?.filters?.impls ?? {}; - } - }) - ), cacheHint: (() => { const cacheHint = listsConfig[listKey].graphql?.cacheHint; if (cacheHint === undefined) { diff --git a/packages/keystone/src/lib/core/where-inputs.ts b/packages/keystone/src/lib/core/where-inputs.ts index 3228f89e657..e6bfab810c6 100644 --- a/packages/keystone/src/lib/core/where-inputs.ts +++ b/packages/keystone/src/lib/core/where-inputs.ts @@ -1,5 +1,6 @@ -import { KeystoneContext } from '@keystone-next/types'; +import { DBField, KeystoneContext } from '@keystone-next/types'; import { InitialisedList } from './types-for-lists'; +import { getDBFieldKeyForFieldOnMultiField } from './utils'; export type InputFilter = Record & { _____?: 'input filter'; @@ -47,20 +48,91 @@ export async function resolveUniqueWhereInput( export async function resolveWhereInput( inputFilter: InputFilter, - list: InitialisedList + list: InitialisedList, + context: KeystoneContext ): Promise { return { AND: await Promise.all( Object.entries(inputFilter).map(async ([fieldKey, value]) => { - if (fieldKey === 'OR' || fieldKey === 'AND') { + if (fieldKey === 'OR' || fieldKey === 'AND' || fieldKey === 'NOT') { return { [fieldKey]: await Promise.all( - value.map((value: any) => resolveWhereInput(value, list)) + value.map((value: any) => resolveWhereInput(value, list, context)) ), }; } - return list.filterImpls[fieldKey](value); + const field = list.fields[fieldKey]; + // we know if there are filters in the input object with the key of a field, the field must have defined a where input so this non null assertion is okay + const where = field.input!.where!; + const dbField = field.dbField; + const ret = where.resolve + ? await where.resolve( + value, + context, + (() => { + if (field.dbField.kind !== 'relation') { + return undefined as any; + } + const foreignList = field.dbField.list; + const whereResolver = (val: any) => + resolveWhereInput(val, list.lists[foreignList], context); + if (field.dbField.mode === 'many') { + return async () => { + if (value === null) { + throw new Error('A many relation filter cannot be set to null'); + } + return Object.fromEntries( + await Promise.all( + Object.entries(value).map(async ([key, val]) => { + if (val === null) { + throw new Error( + `The key ${key} in a many relation filter cannot be set to null` + ); + } + return [key, await whereResolver(val as any)]; + }) + ) + ); + }; + } + return (val: any) => { + if (val === null) { + return null; + } + return whereResolver(val); + }; + })() + ) + : value; + if (ret === null) { + if (field.dbField.kind === 'multi') { + throw new Error('multi db fields cannot return null from where input resolvers'); + } + return { [fieldKey]: null }; + } + return handleOperators(fieldKey, dbField, ret); }) ), }; } + +function handleOperators(fieldKey: string, dbField: DBField, { AND, OR, NOT, ...rest }: any) { + return { + AND: AND?.map((value: any) => handleOperators(fieldKey, dbField, value)), + OR: OR?.map((value: any) => handleOperators(fieldKey, dbField, value)), + NOT: NOT?.map((value: any) => handleOperators(fieldKey, dbField, value)), + ...nestWithAppropiateField(fieldKey, dbField, rest), + }; +} + +function nestWithAppropiateField(fieldKey: string, dbField: DBField, value: any) { + if (dbField.kind === 'multi') { + return Object.fromEntries( + Object.entries(value).map(([key, val]) => [ + getDBFieldKeyForFieldOnMultiField(fieldKey, key), + val, + ]) + ); + } + return { [fieldKey]: value }; +} diff --git a/packages/keystone/src/lib/id-field.ts b/packages/keystone/src/lib/id-field.ts index 39065785c9d..5f3fd34136f 100644 --- a/packages/keystone/src/lib/id-field.ts +++ b/packages/keystone/src/lib/id-field.ts @@ -43,6 +43,63 @@ const idParsers = { }, }; +const nonCircularFields = { + equals: schema.arg({ type: schema.ID }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.ID)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.ID)) }), + lt: schema.arg({ type: schema.ID }), + lte: schema.arg({ type: schema.ID }), + gt: schema.arg({ type: schema.ID }), + gte: schema.arg({ type: schema.ID }), +}; + +type IDFilterType = schema.InputObjectType< + typeof nonCircularFields & { + not: schema.Arg; + } +>; + +const IDFilter: IDFilterType = schema.inputObject({ + name: 'IDFilter', + fields: () => ({ + ...nonCircularFields, + not: schema.arg({ type: IDFilter }), + }), +}); + +const filterArg = schema.arg({ type: IDFilter }); + +function resolveVal( + input: Exclude, undefined>, + kind: IdFieldConfig['kind'] +): any { + if (input === null) { + throw new Error('id filter cannot be null'); + } + const idParser = idParsers[kind]; + const obj: any = {}; + for (const key of ['equals', 'gt', 'gte', 'lt', 'lte'] as const) { + const val = input[key]; + if (val !== undefined) { + const parsed = idParser(val); + obj[key] = parsed; + } + } + for (const key of ['in', 'notIn'] as const) { + const val = input[key]; + if (val !== undefined) { + if (val === null) { + throw new Error(`${key} id filter cannot be null`); + } + obj[key] = val.map(x => idParser(x)); + } + } + if (input.not !== undefined) { + obj.not = resolveVal(input.not, kind); + } + return obj; +} + export const idFieldType = (config: IdFieldConfig): FieldTypeFunc => meta => { @@ -55,6 +112,12 @@ export const idFieldType = default: { kind: config.kind }, })({ input: { + where: { + arg: filterArg, + resolve(val) { + return resolveVal(val, config.kind); + }, + }, uniqueWhere: { arg: schema.arg({ type: schema.ID }), resolve: parseVal }, orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, }, diff --git a/packages/keystone/src/lib/server/createApolloServer.ts b/packages/keystone/src/lib/server/createApolloServer.ts index 70cce699e4d..af4d51b3985 100644 --- a/packages/keystone/src/lib/server/createApolloServer.ts +++ b/packages/keystone/src/lib/server/createApolloServer.ts @@ -1,22 +1,22 @@ import type { IncomingMessage, ServerResponse } from 'http'; -import { GraphQLSchema } from 'graphql'; +import { GraphQLError, GraphQLSchema } from 'graphql'; import { ApolloServer as ApolloServerMicro } from 'apollo-server-micro'; import { ApolloServer as ApolloServerExpress } from 'apollo-server-express'; import type { Config } from 'apollo-server-express'; -import type { CreateContext, SessionStrategy } from '@keystone-next/types'; +import type { CreateContext, GraphQLConfig, SessionStrategy } from '@keystone-next/types'; import { createSessionContext } from '../../session'; export const createApolloServerMicro = ({ graphQLSchema, createContext, sessionStrategy, - apolloConfig, + graphqlConfig, connectionPromise, }: { graphQLSchema: GraphQLSchema; createContext: CreateContext; sessionStrategy?: SessionStrategy; - apolloConfig?: Config; + graphqlConfig?: GraphQLConfig; connectionPromise: Promise; }) => { const context = async ({ req, res }: { req: IncomingMessage; res: ServerResponse }) => { @@ -28,7 +28,7 @@ export const createApolloServerMicro = ({ req, }); }; - const serverConfig = _createApolloServerConfig({ graphQLSchema, apolloConfig }); + const serverConfig = _createApolloServerConfig({ graphQLSchema, graphqlConfig }); return new ApolloServerMicro({ ...serverConfig, context }); }; @@ -36,12 +36,12 @@ export const createApolloServerExpress = ({ graphQLSchema, createContext, sessionStrategy, - apolloConfig, + graphqlConfig, }: { graphQLSchema: GraphQLSchema; createContext: CreateContext; sessionStrategy?: SessionStrategy; - apolloConfig?: Config; + graphqlConfig?: GraphQLConfig; }) => { const context = async ({ req, res }: { req: IncomingMessage; res: ServerResponse }) => createContext({ @@ -50,18 +50,19 @@ export const createApolloServerExpress = ({ : undefined, req, }); - const serverConfig = _createApolloServerConfig({ graphQLSchema, apolloConfig }); + const serverConfig = _createApolloServerConfig({ graphQLSchema, graphqlConfig }); return new ApolloServerExpress({ ...serverConfig, context }); }; const _createApolloServerConfig = ({ graphQLSchema, - apolloConfig, + graphqlConfig, }: { graphQLSchema: GraphQLSchema; - apolloConfig?: Config; + graphqlConfig?: GraphQLConfig; }) => { // Playground config, is /api/graphql available? + const apolloConfig = graphqlConfig?.apolloConfig; const pp = apolloConfig?.playground; let playground: Config['playground']; const settings = { 'request.credentials': 'same-origin' }; @@ -86,6 +87,7 @@ const _createApolloServerConfig = ({ return { uploads: false, schema: graphQLSchema, + debug: graphqlConfig?.debug, // If undefined, use Apollo default of NODE_ENV !== 'production' // FIXME: support for apollo studio tracing // ...(process.env.ENGINE_API_KEY || process.env.APOLLO_KEY // ? { tracing: true } @@ -97,6 +99,7 @@ const _createApolloServerConfig = ({ // tracing: dev, // }), ...apolloConfig, + formatError: formatError(graphqlConfig), // Carefully inject the playground playground, // FIXME: Support for file handling configuration @@ -104,3 +107,24 @@ const _createApolloServerConfig = ({ // maxFiles: 5, }; }; + +const formatError = (graphqlConfig: GraphQLConfig | undefined) => { + return (err: GraphQLError) => { + let debug = graphqlConfig?.debug; + if (debug === undefined) { + debug = process.env.NODE_ENV !== 'production'; + } + + if (!debug && err.extensions) { + // Strip out any `debug` extensions + delete err.extensions.debug; + delete err.extensions.exception; + } + + if (graphqlConfig?.apolloConfig?.formatError) { + return graphqlConfig.apolloConfig.formatError(err); + } else { + return err; + } + }; +}; diff --git a/packages/keystone/src/lib/server/createExpressServer.ts b/packages/keystone/src/lib/server/createExpressServer.ts index f4342538093..e94fe7c1297 100644 --- a/packages/keystone/src/lib/server/createExpressServer.ts +++ b/packages/keystone/src/lib/server/createExpressServer.ts @@ -1,9 +1,13 @@ -import type { Config } from 'apollo-server-express'; import cors, { CorsOptions } from 'cors'; import express from 'express'; import { GraphQLSchema } from 'graphql'; import { graphqlUploadExpress } from 'graphql-upload'; -import type { KeystoneConfig, CreateContext, SessionStrategy } from '@keystone-next/types'; +import type { + KeystoneConfig, + CreateContext, + SessionStrategy, + GraphQLConfig, +} from '@keystone-next/types'; import { createAdminUIServer } from '../../admin-ui/system'; import { createApolloServerExpress } from './createApolloServer'; import { addHealthCheck } from './addHealthCheck'; @@ -16,20 +20,20 @@ const addApolloServer = ({ graphQLSchema, createContext, sessionStrategy, - apolloConfig, + graphqlConfig, }: { server: express.Express; config: KeystoneConfig; graphQLSchema: GraphQLSchema; createContext: CreateContext; sessionStrategy?: SessionStrategy; - apolloConfig?: Config; + graphqlConfig?: GraphQLConfig; }) => { const apolloServer = createApolloServerExpress({ graphQLSchema, createContext, sessionStrategy, - apolloConfig, + graphqlConfig, }); const maxFileSize = config.server?.maxFileSize || DEFAULT_MAX_FILE_SIZE; @@ -68,7 +72,7 @@ export const createExpressServer = async ( graphQLSchema, createContext, sessionStrategy: config.session, - apolloConfig: config.graphql?.apolloConfig, + graphqlConfig: config.graphql, }); if (config.ui?.isDisabled) { diff --git a/packages/keystone/src/schema/schema.ts b/packages/keystone/src/schema/schema.ts index c3694e83b19..1c84166a776 100644 --- a/packages/keystone/src/schema/schema.ts +++ b/packages/keystone/src/schema/schema.ts @@ -1,5 +1,5 @@ import type { GraphQLSchema } from 'graphql'; -import { mergeSchemas } from '@graphql-tools/merge'; +import { mergeSchemas } from '@graphql-tools/schema'; import type { BaseFields, diff --git a/packages/keystone/src/scripts/tests/__snapshots__/artifacts.test.ts.snap b/packages/keystone/src/scripts/tests/__snapshots__/artifacts.test.ts.snap index d82fd130fba..40457901eb3 100644 --- a/packages/keystone/src/scripts/tests/__snapshots__/artifacts.test.ts.snap +++ b/packages/keystone/src/scripts/tests/__snapshots__/artifacts.test.ts.snap @@ -19,28 +19,48 @@ type Scalars = { export type TodoWhereInput = { readonly AND?: ReadonlyArray | TodoWhereInput | null; readonly OR?: ReadonlyArray | TodoWhereInput | null; - readonly id?: Scalars['ID'] | null; - readonly id_not?: Scalars['ID'] | null; - readonly id_lt?: Scalars['ID'] | null; - readonly id_lte?: Scalars['ID'] | null; - readonly id_gt?: Scalars['ID'] | null; - readonly id_gte?: Scalars['ID'] | null; - readonly id_in?: ReadonlyArray | Scalars['ID'] | null; - readonly id_not_in?: ReadonlyArray | Scalars['ID'] | null; - readonly title?: Scalars['String'] | null; - readonly title_not?: Scalars['String'] | null; - readonly title_contains?: Scalars['String'] | null; - readonly title_not_contains?: Scalars['String'] | null; - readonly title_in?: - | ReadonlyArray - | Scalars['String'] - | null - | null; - readonly title_not_in?: - | ReadonlyArray - | Scalars['String'] - | null - | null; + readonly NOT?: ReadonlyArray | TodoWhereInput | null; + readonly id?: IDFilter | null; + readonly title?: StringNullableFilter | null; +}; + +export type IDFilter = { + readonly equals?: Scalars['ID'] | null; + readonly in?: ReadonlyArray | Scalars['ID'] | null; + readonly notIn?: ReadonlyArray | Scalars['ID'] | null; + readonly lt?: Scalars['ID'] | null; + readonly lte?: Scalars['ID'] | null; + readonly gt?: Scalars['ID'] | null; + readonly gte?: Scalars['ID'] | null; + readonly not?: IDFilter | null; +}; + +export type StringNullableFilter = { + readonly equals?: Scalars['String'] | null; + readonly in?: ReadonlyArray | Scalars['String'] | null; + readonly notIn?: ReadonlyArray | Scalars['String'] | null; + readonly lt?: Scalars['String'] | null; + readonly lte?: Scalars['String'] | null; + readonly gt?: Scalars['String'] | null; + readonly gte?: Scalars['String'] | null; + readonly contains?: Scalars['String'] | null; + readonly startsWith?: Scalars['String'] | null; + readonly endsWith?: Scalars['String'] | null; + readonly not?: NestedStringNullableFilter | null; +}; + +export type NestedStringNullableFilter = { + readonly equals?: Scalars['String'] | null; + readonly in?: ReadonlyArray | Scalars['String'] | null; + readonly notIn?: ReadonlyArray | Scalars['String'] | null; + readonly lt?: Scalars['String'] | null; + readonly lte?: Scalars['String'] | null; + readonly gt?: Scalars['String'] | null; + readonly gte?: Scalars['String'] | null; + readonly contains?: Scalars['String'] | null; + readonly startsWith?: Scalars['String'] | null; + readonly endsWith?: Scalars['String'] | null; + readonly not?: NestedStringNullableFilter | null; }; export type TodoWhereUniqueInput = { @@ -94,7 +114,7 @@ export type TodoListTypeInfo = { listQuery: { readonly where?: TodoWhereInput; readonly orderBy?: ReadonlyArray | TodoOrderByInput; - readonly first?: Scalars['Int'] | null; + readonly take?: Scalars['Int'] | null; readonly skip?: Scalars['Int']; }; }; diff --git a/packages/keystone/src/scripts/tests/build.test.ts b/packages/keystone/src/scripts/tests/build.test.ts index 97908231a12..46c5b16a45e 100644 --- a/packages/keystone/src/scripts/tests/build.test.ts +++ b/packages/keystone/src/scripts/tests/build.test.ts @@ -77,7 +77,7 @@ test('build works with typescript without the user defining a babel config', asy ✨ Generating Keystone config code ✨ Building Admin UI info - Using webpack 4. Reason: custom webpack configuration in next.config.js https://nextjs.org/docs/messages/webpack5 - info - Checking validity of types... + info - Skipping validation of types... info - Creating an optimized production build... info - Compiled successfully info - Collecting page data... diff --git a/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql b/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql index 2f3cfe2ec31..b0e148762fd 100644 --- a/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql +++ b/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql @@ -6,20 +6,48 @@ type Todo { input TodoWhereInput { AND: [TodoWhereInput!] OR: [TodoWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - title: String - title_not: String - title_contains: String - title_not_contains: String - title_in: [String] - title_not_in: [String] + NOT: [TodoWhereInput!] + id: IDFilter + title: StringNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } input TodoWhereUniqueInput { @@ -70,7 +98,7 @@ type Query { todos( where: TodoWhereInput! = {} orderBy: [TodoOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Todo!] todo(where: TodoWhereUniqueInput!): Todo diff --git a/packages/keystone/src/session/index.ts b/packages/keystone/src/session/index.ts index 3f16ecd60f2..9843ebe8c9b 100644 --- a/packages/keystone/src/session/index.ts +++ b/packages/keystone/src/session/index.ts @@ -87,11 +87,12 @@ export function statelessSessions({ } return { async get({ req }) { - if (!req.headers.cookie) return; - let cookies = cookie.parse(req.headers.cookie); - if (!cookies[TOKEN_NAME]) return; + const cookies = cookie.parse(req.headers.cookie || ''); + const bearer = req.headers.authorization?.replace('Bearer ', ''); + const token = bearer || cookies[TOKEN_NAME]; + if (!token) return; try { - return await Iron.unseal(cookies[TOKEN_NAME], secret, ironOptions); + return await Iron.unseal(token, secret, ironOptions); } catch (err) {} }, async end({ res }) { diff --git a/packages/session-store-redis/package.json b/packages/session-store-redis/package.json index 201aa83296d..32396318b80 100644 --- a/packages/session-store-redis/package.json +++ b/packages/session-store-redis/package.json @@ -8,7 +8,7 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.14.8", + "@babel/runtime": "^7.15.3", "@types/redis": "^2.8.31" }, "devDependencies": { diff --git a/packages/testing/CHANGELOG.md b/packages/testing/CHANGELOG.md index 1f2b8df452e..1b73d7bd019 100644 --- a/packages/testing/CHANGELOG.md +++ b/packages/testing/CHANGELOG.md @@ -1,5 +1,12 @@ # @keystone-next/testing +## 1.1.1 + +### Patch Changes + +- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/keystone@24.0.0 + ## 1.1.0 ### Minor Changes diff --git a/packages/testing/package.json b/packages/testing/package.json index fc0d46f2c7f..4e1827333ea 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,7 +1,7 @@ { "name": "@keystone-next/testing", "description": "Tools to assist with testing Keystone projects", - "version": "1.1.0", + "version": "1.1.1", "author": "The KeystoneJS Development Team", "license": "MIT", "main": "dist/testing.cjs.js", @@ -10,11 +10,11 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@keystone-next/keystone": "^23.0.0", + "@keystone-next/keystone": "^24.0.0", "@types/supertest": "^2.0.11", "express": "^4.17.1", "memoize-one": "^5.2.1", - "supertest": "^6.1.4" + "supertest": "^6.1.5" }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/testing" } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index b192772357c..152cc92c772 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,131 @@ # @keystone-next/types +## 24.0.0 + +### Major Changes + +- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `_ListKeyMeta` and `_toManyRelationshipFieldMeta` fields. You should use `listKeyCount` and `toManyRelationshipFieldCount` instead + +* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed all arguments from `context.lists.List.count` and `context.db.lists.List.count` except for `where`. + +- [#6266](https://github.com/keystonejs/keystone/pull/6266) [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Renamed `first` argument in find many queries to `take` to align with Prisma. + + ```graphql + type Query { + users( + where: UserWhereInput! = {} + orderBy: [UserOrderByInput!]! = [] + # previously was first: Int + take: Int + skip: Int! = 0 + ): [User!] + # ... + } + + type User { + # ... + posts( + where: PostWhereInput! = {} + orderBy: [PostOrderByInput!]! = [] + # previously was first: Int + take: Int + skip: Int! = 0 + ): [Post!] + # ... + } + ``` + +* [#6208](https://github.com/keystonejs/keystone/pull/6208) [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The create one mutation now requires a non-null `data` argument and the create many mutation accepts a list of `ItemCreateInput` directly instead of being nested inside of an object with the `ItemCreateInput` in a `data` field. + + If you have a list called `Item`, `createItem` now looks like `createItem(data: ItemCreateInput!): Item` and `createItems` now looks like `createItems(data: [ItemCreateInput!]!): [Item]`. + +- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `search` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `contains` filters instead. + +* [#6095](https://github.com/keystonejs/keystone/pull/6095) [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information. + + ```graphql + query { + posts(where: { title: { contains: "Something" } }) { + title + content + } + } + ``` + +- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `sortBy` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `orderBy` instead. + +* [#6312](https://github.com/keystonejs/keystone/pull/6312) [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated `@graphql-ts/schema`. The second type parameter of `schema.Arg` exported from `@keystone-next/types` is now a boolean that defines whether or not the arg has a default value to make it easier to define circular input objects. + +- [#6217](https://github.com/keystonejs/keystone/pull/6217) [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been renamed to `disconnect` in to-one relationship inputs and the old `disconnect` field has been removed. There are also seperate input types for create and update where the input for create doesn't have `disconnect`. It's also now required that if you provide a to-one relationship input, you must provide exactly one field to the input. + + If you have a list called `Item`, the to-one relationship inputs now look like this: + + ```graphql + input ItemRelateToOneForCreateInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + } + input ItemRelateToOneForUpdateInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + disconnect: Boolean + } + ``` + +* [#6224](https://github.com/keystonejs/keystone/pull/6224) [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been replaced by `set` in to-many relationship inputs, the equivalent to `disconnectAll: true` is now `set: []`. There are also seperate input types for create and update where the input for create doesn't have `disconnect` or `set`. The inputs in the lists in the input field are now also non-null. + + If you have a list called `Item`, the to-many relationship inputs now look like this: + + ```graphql + input ItemRelateToManyForCreateInput { + create: [ItemCreateInput!] + connect: [ItemWhereUniqueInput!] + } + input ItemRelateToManyForUpdateInput { + disconnect: [ItemWhereUniqueInput!] + set: [ItemWhereUniqueInput!] + create: [ItemCreateInput!] + connect: [ItemWhereUniqueInput!] + } + ``` + +- [#6197](https://github.com/keystonejs/keystone/pull/6197) [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. + + If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. + + Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. + +* [#6211](https://github.com/keystonejs/keystone/pull/6211) [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. + + If you have a list called `Item`, the update mutations now look like this: + + ```graphql + type Mutation { + updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item + updateItems(data: [ItemUpdateArgs!]!): [Item] + } + + input ItemUpdateArgs { + where: ItemWhereUniqueInput! + data: ItemUpdateInput! + } + ``` + +- [#6206](https://github.com/keystonejs/keystone/pull/6206) [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The delete mutations now accept `where` unique inputs instead of only an `id`. + + If you have a list called `Item`, `deleteItem` now looks like `deleteItem(where: ItemWhereUniqueInput!): Item` and `deleteItems` now looks like `deleteItems(where: [ItemWhereUniqueInput!]!): [Item]` + +### Minor Changes + +- [#6267](https://github.com/keystonejs/keystone/pull/6267) [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590) Thanks [@timleslie](https://github.com/timleslie)! - Added `config.graphql.debug` option, which can be used to control whether debug information such as stack traces are included in the errors returned by the GraphQL API. + +### Patch Changes + +- [#6249](https://github.com/keystonejs/keystone/pull/6249) [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2) Thanks [@timleslie](https://github.com/timleslie)! - Updated types to allow the `'id'` field in `ui.labelField`, `ui.listView.initialColumns`, and `ui.listView.initialSort`. + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e)]: + - @keystone-next/fields@14.0.0 + ## 23.0.0 ### Major Changes diff --git a/packages/types/package.json b/packages/types/package.json index ec7047c5305..e3fadba83dd 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/types", - "version": "23.0.0", + "version": "24.0.0", "license": "MIT", "main": "dist/types.cjs.js", "module": "dist/types.esm.js", @@ -8,8 +8,9 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@graphql-ts/schema": "0.1.2", - "@keystone-next/fields": "^13.0.0", + "@babel/runtime": "^7.15.3", + "@graphql-ts/schema": "0.2.0", + "@keystone-next/fields": "^14.0.0", "apollo-server-types": "^0.9.0", "cors": "^2.8.5", "decimal.js": "10.3.1", diff --git a/packages/types/src/config/index.ts b/packages/types/src/config/index.ts index 0717d6c62aa..c7023c74d30 100644 --- a/packages/types/src/config/index.ts +++ b/packages/types/src/config/index.ts @@ -143,6 +143,40 @@ export type GraphQLConfig = { * @see https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor */ apolloConfig?: Config; + /* + * When an error is returned from the GraphQL API, Apollo can include a stacktrace + * indicating where the error occurred. When Keystone is processing mutations, it + * will sometimes captures more than one error at a time, and then group these into + * a single error returned from the GraphQL API. Each of these errors will include + * a stacktrace. + * + * In general both categories of stacktrace are useful for debugging while developing, + * but should not be exposed in production, and this is the default behaviour of Keystone. + * + * You can use the `debug` option to change this behaviour. A use case for this + * would be if you need to send the stacktraces to a log, but do not want to return them + * from the API. In this case you could set `debug: true` and use + * `apolloConfig.formatError` to log the stacktraces and then strip them out before + * returning the error. + * + * ``` + * graphql: { + * debug: true, + * apolloConfig: { + * formatError: err => { + * console.error(err); + * delete err.extensions?.errors; + * delete err.extensions?.exception?.errors; + * delete err.extensions?.exception?.stacktrace; + * return err; + * }, + * }, + * } + * ``` + * * + * Default: process.env.NODE_ENV !== 'production' + */ + debug?: boolean; }; // config.extendGraphqlSchema diff --git a/packages/types/src/filters/enum-filter.ts b/packages/types/src/filters/enum-filter.ts new file mode 100644 index 00000000000..c6d91228411 --- /dev/null +++ b/packages/types/src/filters/enum-filter.ts @@ -0,0 +1,76 @@ +import { schema } from '../schema'; + +// yes, these two types have the fields but they're semantically different types +// (even though, yes, having EnumFilter by defined as EnumNullableFilter, would be the same type but names would show up differently in editors for example) + +export type EnumNullableFilter> = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + // can be null + not: schema.Arg>; +}>; + +export type EnumFilter> = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + not: schema.Arg>; +}>; + +type EnumNullableListFilterType> = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +export function enumFilters>( + enumType: Enum +): { + optional: EnumNullableFilter; + required: EnumFilter; + many: EnumNullableListFilterType; +} { + const optional: EnumNullableFilter = schema.inputObject({ + name: `${enumType.graphQLType.name}NullableFilter`, + fields: () => ({ + equals: schema.arg({ type: enumType }), + in: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + not: schema.arg({ type: optional }), + }), + }); + const required: EnumFilter = schema.inputObject({ + name: `${enumType.graphQLType.name}Filter`, + fields: () => ({ + equals: schema.arg({ type: enumType }), + in: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + not: schema.arg({ type: optional }), + }), + }); + const many: EnumNullableListFilterType = schema.inputObject({ + name: `${enumType.graphQLType.name}NullableListFilter`, + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + // can be null + has: schema.arg({ type: enumType }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(enumType)) }), + isEmpty: schema.arg({ type: enumType }), + }), + }); + return { + optional, + required, + many, + }; +} diff --git a/packages/types/src/filters/index.ts b/packages/types/src/filters/index.ts new file mode 100644 index 00000000000..a83f16933d1 --- /dev/null +++ b/packages/types/src/filters/index.ts @@ -0,0 +1,88 @@ +export * as postgresql from './providers/postgresql'; +export * as sqlite from './providers/sqlite'; + +type EntriesAssumingNoExtraProps = { + [Key in keyof T]-?: [Key, T[Key]]; +}[keyof T][]; + +const objectEntriesButAssumeNoExtraProperties: (obj: T) => EntriesAssumingNoExtraProps = + Object.entries as any; + +type CommonFilter = { + equals?: T | null; + in?: readonly T[] | null; + notIn?: readonly T[] | null; + lt?: T | null; + lte?: T | null; + gt?: T | null; + gte?: T | null; + contains?: T | null; + startsWith?: T | null; + endsWith?: T | null; + not?: CommonFilter | null; +}; + +function internalResolveFilter( + entries: EntriesAssumingNoExtraProps>, + mode: 'default' | 'insensitive' | undefined +): object { + const entry = entries.shift(); + if (entry === undefined) return {}; + const [key, val] = entry; + if (val == null) { + return { + AND: [{ [key]: val }, internalResolveFilter(entries, mode)], + }; + } + switch (key) { + case 'equals': + case 'lt': + case 'lte': + case 'gt': + case 'gte': + case 'in': + case 'contains': + case 'startsWith': + case 'endsWith': { + return { + AND: [{ [key]: val, mode }, { not: null }, internalResolveFilter(entries, mode)], + }; + } + + case 'notIn': { + return { + AND: [ + { + NOT: [ + internalResolveFilter(objectEntriesButAssumeNoExtraProperties({ in: val }), mode), + ], + }, + internalResolveFilter(entries, mode), + ], + }; + } + case 'not': { + return { + AND: [ + { + NOT: [internalResolveFilter(objectEntriesButAssumeNoExtraProperties(val) as any, mode)], + }, + internalResolveFilter(entries, mode), + ], + }; + } + } +} + +export function resolveCommon(val: CommonFilter | null) { + if (val === null) return null; + return internalResolveFilter(objectEntriesButAssumeNoExtraProperties(val), undefined); +} + +export function resolveString( + val: (CommonFilter & { mode?: 'default' | 'insensitive' | null }) | null +) { + if (val === null) return null; + let { mode, ...rest } = val; + return internalResolveFilter(objectEntriesButAssumeNoExtraProperties(rest), mode as any); +} diff --git a/packages/types/src/filters/providers/postgresql.ts b/packages/types/src/filters/providers/postgresql.ts new file mode 100644 index 00000000000..cac24d557da --- /dev/null +++ b/packages/types/src/filters/providers/postgresql.ts @@ -0,0 +1,647 @@ +// Do not manually modify this file, it is automatically generated by the package at /prisma-utils in this repo. +// Update the script if you need this file to be different + +import { schema } from '../../schema'; + +import { QueryMode } from '../..'; + +type StringNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + mode: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const StringNullableFilter: StringNullableFilterType = schema.inputObject({ + name: 'StringNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + mode: schema.arg({ type: QueryMode }), + // can be null + not: schema.arg({ type: NestedStringNullableFilter }), + }), +}); + +type NestedStringNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const NestedStringNullableFilter: NestedStringNullableFilterType = schema.inputObject({ + name: 'NestedStringNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: NestedStringNullableFilter }), + }), +}); + +type StringFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + mode: schema.Arg; + not: schema.Arg; +}>; + +const StringFilter: StringFilterType = schema.inputObject({ + name: 'StringFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + mode: schema.arg({ type: QueryMode }), + not: schema.arg({ type: NestedStringFilter }), + }), +}); + +type NestedStringFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + not: schema.Arg; +}>; + +const NestedStringFilter: NestedStringFilterType = schema.inputObject({ + name: 'NestedStringFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + not: schema.arg({ type: NestedStringFilter }), + }), +}); + +type StringNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const StringNullableListFilter: StringNullableListFilterType = schema.inputObject({ + name: 'StringNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + has: schema.arg({ type: schema.String }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +type BoolNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const BoolNullableFilter: BoolNullableFilterType = schema.inputObject({ + name: 'BooleanNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.Boolean }), + // can be null + not: schema.arg({ type: BoolNullableFilter }), + }), +}); + +type BoolFilterType = schema.InputObjectType<{ + equals: schema.Arg; + not: schema.Arg; +}>; + +const BoolFilter: BoolFilterType = schema.inputObject({ + name: 'BooleanFilter', + fields: () => ({ + equals: schema.arg({ type: schema.Boolean }), + not: schema.arg({ type: BoolFilter }), + }), +}); + +type BoolNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const BoolNullableListFilter: BoolNullableListFilterType = schema.inputObject({ + name: 'BooleanNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.Boolean)) }), + // can be null + has: schema.arg({ type: schema.Boolean }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.Boolean)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.Boolean)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +type IntNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const IntNullableFilter: IntNullableFilterType = schema.inputObject({ + name: 'IntNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.Int }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + lt: schema.arg({ type: schema.Int }), + lte: schema.arg({ type: schema.Int }), + gt: schema.arg({ type: schema.Int }), + gte: schema.arg({ type: schema.Int }), + // can be null + not: schema.arg({ type: IntNullableFilter }), + }), +}); + +type IntFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const IntFilter: IntFilterType = schema.inputObject({ + name: 'IntFilter', + fields: () => ({ + equals: schema.arg({ type: schema.Int }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + lt: schema.arg({ type: schema.Int }), + lte: schema.arg({ type: schema.Int }), + gt: schema.arg({ type: schema.Int }), + gte: schema.arg({ type: schema.Int }), + not: schema.arg({ type: IntFilter }), + }), +}); + +type IntNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const IntNullableListFilter: IntNullableListFilterType = schema.inputObject({ + name: 'IntNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + // can be null + has: schema.arg({ type: schema.Int }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +type FloatNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const FloatNullableFilter: FloatNullableFilterType = schema.inputObject({ + name: 'FloatNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.Float }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + lt: schema.arg({ type: schema.Float }), + lte: schema.arg({ type: schema.Float }), + gt: schema.arg({ type: schema.Float }), + gte: schema.arg({ type: schema.Float }), + // can be null + not: schema.arg({ type: FloatNullableFilter }), + }), +}); + +type FloatFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const FloatFilter: FloatFilterType = schema.inputObject({ + name: 'FloatFilter', + fields: () => ({ + equals: schema.arg({ type: schema.Float }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + lt: schema.arg({ type: schema.Float }), + lte: schema.arg({ type: schema.Float }), + gt: schema.arg({ type: schema.Float }), + gte: schema.arg({ type: schema.Float }), + not: schema.arg({ type: FloatFilter }), + }), +}); + +type FloatNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const FloatNullableListFilter: FloatNullableListFilterType = schema.inputObject({ + name: 'FloatNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + // can be null + has: schema.arg({ type: schema.Float }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +type DateTimeNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const DateTimeNullableFilter: DateTimeNullableFilterType = schema.inputObject({ + name: 'DateTimeNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: DateTimeNullableFilter }), + }), +}); + +type DateTimeFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const DateTimeFilter: DateTimeFilterType = schema.inputObject({ + name: 'DateTimeFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + not: schema.arg({ type: DateTimeFilter }), + }), +}); + +type DateTimeNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const DateTimeNullableListFilter: DateTimeNullableListFilterType = schema.inputObject({ + name: 'DateTimeNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + has: schema.arg({ type: schema.String }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +type JsonNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const JsonNullableFilter: JsonNullableFilterType = schema.inputObject({ + name: 'JsonNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.JSON }), + // can be null + not: schema.arg({ type: schema.JSON }), + }), +}); + +type JsonFilterType = schema.InputObjectType<{ + equals: schema.Arg; + not: schema.Arg; +}>; + +const JsonFilter: JsonFilterType = schema.inputObject({ + name: 'JsonFilter', + fields: () => ({ + equals: schema.arg({ type: schema.JSON }), + not: schema.arg({ type: schema.JSON }), + }), +}); + +type JsonNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const JsonNullableListFilter: JsonNullableListFilterType = schema.inputObject({ + name: 'JsonNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.JSON)) }), + // can be null + has: schema.arg({ type: schema.JSON }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.JSON)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.JSON)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +type DecimalNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const DecimalNullableFilter: DecimalNullableFilterType = schema.inputObject({ + name: 'DecimalNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: DecimalNullableFilter }), + }), +}); + +type DecimalFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const DecimalFilter: DecimalFilterType = schema.inputObject({ + name: 'DecimalFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + not: schema.arg({ type: DecimalFilter }), + }), +}); + +type DecimalNullableListFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg>>; + // can be null + has: schema.Arg; + hasEvery: schema.Arg>>; + hasSome: schema.Arg>>; + isEmpty: schema.Arg; +}>; + +const DecimalNullableListFilter: DecimalNullableListFilterType = schema.inputObject({ + name: 'DecimalNullableListFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + has: schema.arg({ type: schema.String }), + hasEvery: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + hasSome: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + isEmpty: schema.arg({ type: schema.Boolean }), + }), +}); + +export const String = { + optional: StringNullableFilter, + required: StringFilter, + many: StringNullableListFilter, +}; + +export const Boolean = { + optional: BoolNullableFilter, + required: BoolFilter, + many: BoolNullableListFilter, +}; + +export const Int = { + optional: IntNullableFilter, + required: IntFilter, + many: IntNullableListFilter, +}; + +export const Float = { + optional: FloatNullableFilter, + required: FloatFilter, + many: FloatNullableListFilter, +}; + +export const DateTime = { + optional: DateTimeNullableFilter, + required: DateTimeFilter, + many: DateTimeNullableListFilter, +}; + +export const Json = { + optional: JsonNullableFilter, + required: JsonFilter, + many: JsonNullableListFilter, +}; + +export const Decimal = { + optional: DecimalNullableFilter, + required: DecimalFilter, + many: DecimalNullableListFilter, +}; + +export { enumFilters as enum } from '../enum-filter'; diff --git a/packages/types/src/filters/providers/sqlite.ts b/packages/types/src/filters/providers/sqlite.ts new file mode 100644 index 00000000000..20591155798 --- /dev/null +++ b/packages/types/src/filters/providers/sqlite.ts @@ -0,0 +1,438 @@ +// Do not manually modify this file, it is automatically generated by the package at /prisma-utils in this repo. +// Update the script if you need this file to be different + +import { schema } from '../../schema'; + +type StringNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const StringNullableFilter: StringNullableFilterType = schema.inputObject({ + name: 'StringNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: NestedStringNullableFilter }), + }), +}); + +type NestedStringNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const NestedStringNullableFilter: NestedStringNullableFilterType = schema.inputObject({ + name: 'NestedStringNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: NestedStringNullableFilter }), + }), +}); + +type StringFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + not: schema.Arg; +}>; + +const StringFilter: StringFilterType = schema.inputObject({ + name: 'StringFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + not: schema.arg({ type: NestedStringFilter }), + }), +}); + +type NestedStringFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + contains: schema.Arg; + startsWith: schema.Arg; + endsWith: schema.Arg; + not: schema.Arg; +}>; + +const NestedStringFilter: NestedStringFilterType = schema.inputObject({ + name: 'NestedStringFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + contains: schema.arg({ type: schema.String }), + startsWith: schema.arg({ type: schema.String }), + endsWith: schema.arg({ type: schema.String }), + not: schema.arg({ type: NestedStringFilter }), + }), +}); + +type BoolNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const BoolNullableFilter: BoolNullableFilterType = schema.inputObject({ + name: 'BooleanNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.Boolean }), + // can be null + not: schema.arg({ type: BoolNullableFilter }), + }), +}); + +type BoolFilterType = schema.InputObjectType<{ + equals: schema.Arg; + not: schema.Arg; +}>; + +const BoolFilter: BoolFilterType = schema.inputObject({ + name: 'BooleanFilter', + fields: () => ({ + equals: schema.arg({ type: schema.Boolean }), + not: schema.arg({ type: BoolFilter }), + }), +}); + +type IntNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const IntNullableFilter: IntNullableFilterType = schema.inputObject({ + name: 'IntNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.Int }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + lt: schema.arg({ type: schema.Int }), + lte: schema.arg({ type: schema.Int }), + gt: schema.arg({ type: schema.Int }), + gte: schema.arg({ type: schema.Int }), + // can be null + not: schema.arg({ type: IntNullableFilter }), + }), +}); + +type IntFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const IntFilter: IntFilterType = schema.inputObject({ + name: 'IntFilter', + fields: () => ({ + equals: schema.arg({ type: schema.Int }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Int)) }), + lt: schema.arg({ type: schema.Int }), + lte: schema.arg({ type: schema.Int }), + gt: schema.arg({ type: schema.Int }), + gte: schema.arg({ type: schema.Int }), + not: schema.arg({ type: IntFilter }), + }), +}); + +type FloatNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const FloatNullableFilter: FloatNullableFilterType = schema.inputObject({ + name: 'FloatNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.Float }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + lt: schema.arg({ type: schema.Float }), + lte: schema.arg({ type: schema.Float }), + gt: schema.arg({ type: schema.Float }), + gte: schema.arg({ type: schema.Float }), + // can be null + not: schema.arg({ type: FloatNullableFilter }), + }), +}); + +type FloatFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const FloatFilter: FloatFilterType = schema.inputObject({ + name: 'FloatFilter', + fields: () => ({ + equals: schema.arg({ type: schema.Float }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.Float)) }), + lt: schema.arg({ type: schema.Float }), + lte: schema.arg({ type: schema.Float }), + gt: schema.arg({ type: schema.Float }), + gte: schema.arg({ type: schema.Float }), + not: schema.arg({ type: FloatFilter }), + }), +}); + +type DateTimeNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const DateTimeNullableFilter: DateTimeNullableFilterType = schema.inputObject({ + name: 'DateTimeNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: DateTimeNullableFilter }), + }), +}); + +type DateTimeFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const DateTimeFilter: DateTimeFilterType = schema.inputObject({ + name: 'DateTimeFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + not: schema.arg({ type: DateTimeFilter }), + }), +}); + +type DecimalNullableFilterType = schema.InputObjectType<{ + // can be null + equals: schema.Arg; + // can be null + in: schema.Arg>>; + // can be null + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + // can be null + not: schema.Arg; +}>; + +const DecimalNullableFilter: DecimalNullableFilterType = schema.inputObject({ + name: 'DecimalNullableFilter', + fields: () => ({ + // can be null + equals: schema.arg({ type: schema.String }), + // can be null + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + // can be null + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + // can be null + not: schema.arg({ type: DecimalNullableFilter }), + }), +}); + +type DecimalFilterType = schema.InputObjectType<{ + equals: schema.Arg; + in: schema.Arg>>; + notIn: schema.Arg>>; + lt: schema.Arg; + lte: schema.Arg; + gt: schema.Arg; + gte: schema.Arg; + not: schema.Arg; +}>; + +const DecimalFilter: DecimalFilterType = schema.inputObject({ + name: 'DecimalFilter', + fields: () => ({ + equals: schema.arg({ type: schema.String }), + in: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + notIn: schema.arg({ type: schema.list(schema.nonNull(schema.String)) }), + lt: schema.arg({ type: schema.String }), + lte: schema.arg({ type: schema.String }), + gt: schema.arg({ type: schema.String }), + gte: schema.arg({ type: schema.String }), + not: schema.arg({ type: DecimalFilter }), + }), +}); + +export const String = { + optional: StringNullableFilter, + required: StringFilter, +}; + +export const Boolean = { + optional: BoolNullableFilter, + required: BoolFilter, +}; + +export const Int = { + optional: IntNullableFilter, + required: IntFilter, +}; + +export const Float = { + optional: FloatNullableFilter, + required: FloatFilter, +}; + +export const DateTime = { + optional: DateTimeNullableFilter, + required: DateTimeFilter, +}; + +export const Decimal = { + optional: DecimalNullableFilter, + required: DecimalFilter, +}; + +export { enumFilters as enum } from '../enum-filter'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index e3a6ce3cb54..a614595cca9 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -7,5 +7,6 @@ export * from './base'; export * from './context'; export * from './next-fields'; export * as legacyFilters from './legacy-filters'; +export * as filters from './filters'; export * from './schema'; export { jsonFieldTypePolyfilledForSQLite } from './json-field-type-polyfill-for-sqlite'; diff --git a/packages/types/src/json-field-type-polyfill-for-sqlite.ts b/packages/types/src/json-field-type-polyfill-for-sqlite.ts index 5ea475b0fed..9ad7a9a307c 100644 --- a/packages/types/src/json-field-type-polyfill-for-sqlite.ts +++ b/packages/types/src/json-field-type-polyfill-for-sqlite.ts @@ -98,8 +98,8 @@ export function jsonFieldTypePolyfilledForSQLite< ScalarDBField<'Json', 'optional'>, CreateArg, UpdateArg, - schema.Arg, - schema.Arg + schema.Arg, + schema.Arg > & { input?: { uniqueWhere?: undefined; diff --git a/packages/types/src/next-fields.ts b/packages/types/src/next-fields.ts index 349b815ed91..645f36b37a8 100644 --- a/packages/types/src/next-fields.ts +++ b/packages/types/src/next-fields.ts @@ -39,17 +39,21 @@ export type NextFieldType< | schema.Arg | undefined, UpdateArg extends schema.Arg = schema.Arg, - UniqueWhereArg extends schema.Arg = schema.Arg< + UniqueWhereArg extends schema.Arg = schema.Arg< schema.NullableInputType, - undefined + false >, - OrderByArg extends schema.Arg = schema.Arg< + OrderByArg extends schema.Arg = schema.Arg< schema.NullableInputType, - undefined + false + >, + FilterArg extends schema.Arg = schema.Arg< + schema.NullableInputType, + false > > = { dbField: TDBField; -} & FieldTypeWithoutDBField; +} & FieldTypeWithoutDBField; type ScalarPrismaTypes = { String: string; @@ -111,6 +115,11 @@ export const orderDirectionEnum = schema.enum({ values: schema.enumValues(['asc', 'desc']), }); +export const QueryMode = schema.enum({ + name: 'QueryMode', + values: schema.enumValues(['default', 'insensitive']), +}); + export type RelationDBField = { kind: 'relation'; list: string; @@ -224,6 +233,39 @@ type FieldInputResolver = ( relationshipInputResolver: RelationshipInputResolver ) => MaybePromise; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type DBFieldFiltersInner = Record; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type DBFieldFilters = + | ({ + AND?: DBFieldFiltersInner; + OR?: DBFieldFiltersInner; + NOT?: DBFieldFiltersInner; + } & DBFieldFiltersInner) + | null; + +export type WhereFieldInputArg< + TDBField extends DBField, + TArg extends schema.Arg +> = { + arg: TArg; +} & ResolveFunc< + FieldInputResolver< + Exclude, undefined>, + DBFieldFilters, + any + // i think this is broken because variance? + // TDBField extends RelationDBField + // ? ( + // input: { + // many: types.InferValueFromArg>; + // one: types.InferValueFromArg>; + // }[Mode] + // ) => Promise + // : undefined + > +>; + export type UpdateFieldInputArg< TDBField extends DBField, TArg extends schema.Arg @@ -309,17 +351,22 @@ export type FieldTypeWithoutDBField< | schema.Arg | undefined, UpdateArg extends schema.Arg = schema.Arg, - UniqueWhereArg extends schema.Arg = schema.Arg< + UniqueWhereArg extends schema.Arg = schema.Arg< schema.NullableInputType, - undefined + false >, - OrderByArg extends schema.Arg = schema.Arg< + OrderByArg extends schema.Arg = schema.Arg< schema.NullableInputType, - undefined + false + >, + FilterArg extends schema.Arg = schema.Arg< + schema.NullableInputType, + false > > = { input?: { uniqueWhere?: UniqueWhereFieldInputArg, UniqueWhereArg>; + where?: WhereFieldInputArg; create?: CreateFieldInputArg; update?: UpdateFieldInputArg; orderBy?: OrderByFieldInputArg, OrderByArg>; @@ -346,10 +393,18 @@ export function fieldType(dbField: TDBField) { return function < CreateArg extends schema.Arg | undefined, UpdateArg extends schema.Arg, - UniqueWhereArg extends schema.Arg, - OrderByArg extends schema.Arg + UniqueWhereArg extends schema.Arg, + OrderByArg extends schema.Arg, + FilterArg extends schema.Arg >( - stuff: FieldTypeWithoutDBField + stuff: FieldTypeWithoutDBField< + TDBField, + CreateArg, + UpdateArg, + UniqueWhereArg, + OrderByArg, + FilterArg + > ): NextFieldType { return { ...stuff, dbField }; }; @@ -367,6 +422,11 @@ export type TypesForList = { findManyArgs: FindManyArgs; relateTo: { many: { + where: schema.InputObjectType<{ + every: schema.Arg; + some: schema.Arg; + none: schema.Arg; + }>; create: schema.InputObjectType<{ connect: schema.Arg>>; create?: schema.Arg>>; @@ -393,13 +453,13 @@ export type TypesForList = { }; export type FindManyArgs = { - where: schema.Arg, {}>; + where: schema.Arg, true>; orderBy: schema.Arg< schema.NonNullType>>, - Record[] + true >; - first: schema.Arg; - skip: schema.Arg, number>; + take: schema.Arg; + skip: schema.Arg, true>; }; export type FindManyArgsValue = schema.InferValueFromArgs; diff --git a/packages/types/src/utils.ts b/packages/types/src/utils.ts index b6aee7d0508..7100c4c35f8 100644 --- a/packages/types/src/utils.ts +++ b/packages/types/src/utils.ts @@ -11,7 +11,7 @@ export type BaseGeneratedListTypes = { args: { listQuery: { readonly where?: GraphQLInput | null; - readonly first?: number | null; + readonly take?: number | null; readonly skip?: number; readonly orderBy?: | Record diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 494c10fdf6f..3e9da6bed6a 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @keystone-next/utils +## 1.0.4 + +### Patch Changes + +- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/types@24.0.0 + ## 1.0.3 ### Patch Changes diff --git a/packages/utils/package.json b/packages/utils/package.json index d7c4246fed3..43197d74571 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,7 +1,7 @@ { "name": "@keystone-next/utils", "description": "Common utility functions used throughout @keystone-next packages.", - "version": "1.0.3", + "version": "1.0.4", "author": "The KeystoneJS Development Team", "license": "MIT", "homepage": "https://github.com/keystonejs/keystone", @@ -11,8 +11,8 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.14.8", - "@keystone-next/types": "^23.0.0" + "@babel/runtime": "^7.15.3", + "@keystone-next/types": "^24.0.0" }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/utils" } diff --git a/prisma-utils/.gitignore b/prisma-utils/.gitignore new file mode 100644 index 00000000000..80697f2272d --- /dev/null +++ b/prisma-utils/.gitignore @@ -0,0 +1 @@ +src/generated \ No newline at end of file diff --git a/prisma-utils/README.md b/prisma-utils/README.md new file mode 100644 index 00000000000..bfe77378a66 --- /dev/null +++ b/prisma-utils/README.md @@ -0,0 +1,5 @@ +# prisma-utils + +This (unpublished) package generates the GraphQL filters for most field types in Keystone from Prisma information. + +You can run it with `yarn generate-filters` from the root, you should run this whenever CI fails because of this which should only be after updating Prisma or the script. diff --git a/prisma-utils/package.json b/prisma-utils/package.json new file mode 100644 index 00000000000..925b4d8e5fa --- /dev/null +++ b/prisma-utils/package.json @@ -0,0 +1,17 @@ +{ + "name": "@keystone-next/prisma-utils", + "version": "0.0.0", + "private": true, + "main": "dist/prisma-utils.cjs.js", + "dependencies": { + "@prisma/generator-helper": "2.29.1", + "@prisma/sdk": "2.29.1", + "fs-extra": "^10.0.0", + "prettier": "^2.3.2" + }, + "scripts": { + "generate": "node .", + "verify": "VERIFY=1 node ." + }, + "repository": "https://github.com/keystonejs/keystone/tree/master/prisma-utils" +} diff --git a/prisma-utils/src/index.ts b/prisma-utils/src/index.ts new file mode 100644 index 00000000000..c4570a8c39f --- /dev/null +++ b/prisma-utils/src/index.ts @@ -0,0 +1,313 @@ +// this file generates the GraphQL filter types for most of our fields. +// generating them from the prisma information isn't really about time or convenience. +// it's about clearly showing what the rules for getting the filters are and what the exceptions are. + +import { deepStrictEqual } from 'assert'; +import { isDeepStrictEqual } from 'util'; +import fs from 'fs-extra'; +import { DMMF } from '@prisma/generator-helper'; +import { getDMMF } from '@prisma/sdk'; +import { format, resolveConfig } from 'prettier'; + +const providers = ['postgresql', 'sqlite'] as const; + +type Provider = typeof providers[number]; + +// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#model-field-scalar-types +// only the prisma scalars that we currently use are here because adding one requires choosing a graphql scalar +// we can add them when we want field types for those scalars +// the missing ones are: +// - Bytes +// - BigInt +// - Unsupported (this one can't be interacted with in the prisma client (and therefore cannot be filtered) so it's irrelevant here) +const scalarTypes = ['String', 'Boolean', 'Int', 'Float', 'DateTime', 'Json', 'Decimal'] as const; + +const getScalarTypesForProvider = (provider: Provider): readonly typeof scalarTypes[number][] => + provider === 'sqlite' ? scalarTypes.filter(x => x !== 'Json') : scalarTypes; + +const getSchemaForProvider = (provider: Provider) => { + const scalarTypesForProvider = getScalarTypesForProvider(provider); + return `datasource ${provider} { + url = env("DATABASE_URL") + provider = "${provider}" +} + +generator client { + provider = "prisma-client-js" +} + +model Optional { + id Int @id @default(autoincrement()) + ${scalarTypesForProvider.map(scalarType => `${scalarType} ${scalarType}?`).join('\n')} +} + +model Required { + id Int @id @default(autoincrement()) + ${scalarTypesForProvider.map(scalarType => `${scalarType} ${scalarType}`).join('\n')} +} + +${ + provider === 'postgresql' + ? `model Many { + id Int @id @default(autoincrement()) + ${scalarTypesForProvider.map(scalarType => `${scalarType} ${scalarType}[]`).join('\n')} +}` + : '' +} + +`; +}; + +(async () => { + const prettierConfig = await resolveConfig(`${__dirname}/index.ts`); + assert(prettierConfig !== null); + for (const provider of providers) { + const schema = getSchemaForProvider(provider); + const dmmf = await getDMMF({ datamodel: schema }); + + await fs.outputFile( + `${__dirname}/generated/${provider}.json`, + JSON.stringify(dmmf.schema.inputObjectTypes, null, 2) + ); + const types = getInputTypesByName(dmmf.schema.inputObjectTypes.prisma); + const rootTypes = getScalarTypesForProvider(provider).flatMap((scalar: string) => { + if (scalar === 'Boolean') { + scalar = 'Bool'; + } + if (scalar === 'SomeEnum') { + // the filter types have to be generic over the enum so it's just easier to write it out manually + // but we still want this here to snapshot what the filters look like for a given prisma version & provider combination + return []; + } + let types = [`${scalar}NullableFilter`, `${scalar}Filter`]; + if (provider === 'postgresql') { + // i'm not sure this is says nullable when they're not nullable? + // i don't think there is a nullable and non-nullable list? + types.push(`${scalar}NullableListFilter`); + } + return types; + }); + for (const typeName of Object.keys(types)) { + replaceNestedNotFilterTypes(types, typeName); + } + const referencedTypes = new Set(); + for (const typeName of rootTypes) { + collectReferencedTypes(types, typeName, referencedTypes); + } + if (provider !== 'sqlite') { + deepStrictEqual( + dmmf.schema.enumTypes.prisma.find(x => x.name === 'QueryMode'), + { name: 'QueryMode', values: ['default', 'insensitive'] } + ); + } + + await fs.outputFile( + `${__dirname}/generated/only-filters/${provider}.json`, + JSON.stringify( + Object.fromEntries([...referencedTypes].map(typeName => [typeName, types[typeName]])), + null, + 2 + ) + ); + const filepath = `${__dirname}/../../packages/types/src/filters/providers/${provider}.ts`; + const newContent = format( + `// Do not manually modify this file, it is automatically generated by the package at /prisma-utils in this repo. +// Update the script if you need this file to be different + + import { schema } from '../../schema'; + + +${provider !== 'sqlite' ? `import { QueryMode } from '../..'` : ''} + +${[...referencedTypes].map(typeName => printInputTypeForGraphQLTS(typeName, types)).join('\n\n')} + +${getScalarTypesForProvider(provider) + .map(scalar => { + const scalarInFilterName = scalar === 'Boolean' ? 'Bool' : scalar; + return `export const ${scalar} = { +optional: ${scalarInFilterName}NullableFilter, +required: ${scalarInFilterName}Filter, +${provider === 'postgresql' ? `many: ${scalarInFilterName}NullableListFilter` : ''} +}`; + }) + .join('\n\n')} + +export {enumFilters as enum } from '../enum-filter' + `, + { ...prettierConfig, filepath } + ); + if (process.env.VERIFY) { + const contents = await fs.readFile(filepath, 'utf8'); + if (contents !== newContent) { + throw new Error( + `The file at ${filepath} is inconsistent with the expected generated contents, please run \`yarn generate-filters\` from the root to update it` + ); + } + } else { + await fs.outputFile(filepath, newContent); + } + } +})().catch(x => { + console.error(x); + process.exit(1); +}); + +function getInputTypesByName(types: DMMF.InputType[]) { + return Object.fromEntries(types.map(x => [x.name, x])); +} + +function assert(condition: boolean, message?: string): asserts condition { + if (!condition) { + debugger; + throw new Error(`assertion failed${message === undefined ? '' : `: ${message}`}`); + } +} + +function replaceNestedNotFilterTypes( + inputTypesByName: Record, + inputTypeName: string +) { + // we want to not replace the nested filter for strings because we don't replace it on postgresql + // and we want the naming to be the same on SQLite + if (inputTypeName.includes('String')) return; + const inputType = inputTypesByName[inputTypeName]; + for (const field of inputType.fields) { + if (field.name === 'not') { + const objectInput = field.inputTypes.find(input => input.namespace === 'prisma'); + if ( + typeof objectInput?.type === 'string' && + isDeepStrictEqual(inputType.fields, inputTypesByName[objectInput.type].fields) + ) { + objectInput.type = inputTypeName; + } + } + } +} + +const expectedScalars = new Set(['Null', 'QueryMode', ...scalarTypes]); + +function collectReferencedTypes( + inputTypesByName: Record, + inputTypeName: string, + referencedTypes: Set +) { + referencedTypes.add(inputTypeName); + const inputType = inputTypesByName[inputTypeName]; + assert(inputType !== undefined, `could not find input type ${inputTypeName}`); + + for (const field of inputType.fields) { + assert(!field.isRequired, 'unexpected required field'); + for (const inputType of field.inputTypes) { + assert(typeof inputType.type === 'string', 'unexpected non-type name in input types'); + if (inputType.location === 'scalar' || inputType.location === 'enumTypes') { + assert(expectedScalars.has(inputType.type), `unexpected scalar ${inputType.type}`); + continue; + } + assert(inputType.location === 'inputObjectTypes', `unexpected ${inputType.location} type`); + if (!referencedTypes.has(inputType.type)) { + collectReferencedTypes(inputTypesByName, inputType.type, referencedTypes); + } + } + } +} + +/** + * Note a field can be both nullable and a list. + * + * Translated into typescript, that means `Array | null`, + * not `Array` or `Array | null` + */ +type TransformedInputTypeField = { + type: string; + isNullable: boolean; + isList: boolean; +}; + +function pickInputTypeForField(field: DMMF.SchemaArg): TransformedInputTypeField { + assert(!field.isRequired, 'unexpected required field'); + // null is already represented with field.isNullable + const inputTypesWithoutNull = field.inputTypes.filter(type => { + if (type.type === 'Null') { + assert(!type.isList, 'unexpected null list'); + assert(field.isNullable, 'unexpected isNullable false when null type in input types'); + return false; + } + return true; + }); + + assert( + inputTypesWithoutNull.length + Number(field.isNullable) === field.inputTypes.length, + 'unexpected isNullable false when null type in input types' + ); + const inputType = (() => { + if (inputTypesWithoutNull.length === 1) { + return inputTypesWithoutNull[0]; + } + assert( + inputTypesWithoutNull.length === 2, + 'unexpected more than two input types excluding null' + ); + const inputType = inputTypesWithoutNull.find(x => x.location == 'inputObjectTypes'); + assert( + !!inputType, + 'could not find input object type when more than one input type excluding null' + ); + return inputType; + })(); + assert(typeof inputType.type === 'string'); + return { + isList: inputType.isList, + isNullable: field.isNullable, + type: scalarsToGqlScalars[inputType.type] ?? inputType.type, + }; +} + +function printInputTypeForGraphQLTS( + inputTypeName: string, + inputTypesByName: Record +) { + const inputType = inputTypesByName[inputTypeName]; + assert(inputType !== undefined, `could not find input type ${inputTypeName}`); + const expectedMaxMinNumFields = inputTypeName.endsWith('NullableListFilter') ? 1 : null; + assert(inputType.constraints.maxNumFields === expectedMaxMinNumFields); + assert(inputType.constraints.minNumFields === expectedMaxMinNumFields); + const nameOfInputObjectTypeType = `${inputTypeName}Type`; + const fields = inputType.fields.map(x => [x.name, pickInputTypeForField(x)] as const); + return `type ${nameOfInputObjectTypeType} = schema.InputObjectType<{ + ${fields + .map(([name, field]) => { + return `${field.isNullable ? '// can be null\n' : ''}${name}: schema.Arg<${ + field.isList + ? `schema.ListType>` + : `typeof ${field.type}` + }>`; + }) + .join(',\n')} + }> + + const ${inputTypeName}: ${nameOfInputObjectTypeType} = schema.inputObject({ + name: '${ + // we want to use Boolean instead of Bool because GraphQL calls it Boolean + inputTypeName.replace('Bool', 'Boolean') + }', + fields: () => ({ + ${fields + .map(([name, field]) => { + return `${field.isNullable ? '// can be null\n' : ''}${name}: schema.arg({ type: ${ + field.isList ? `schema.list(schema.nonNull(${field.type}))` : field.type + } })`; + }) + .join(',\n')} + }) + })`; +} + +const scalarsToGqlScalars: Record = { + String: 'schema.String', + Boolean: 'schema.Boolean', + Int: 'schema.Int', + Float: 'schema.Float', + Json: 'schema.JSON', + DateTime: 'schema.String', + Decimal: 'schema.String', +}; diff --git a/tests/admin-ui-tests/CHANGELOG.md b/tests/admin-ui-tests/CHANGELOG.md index 5cc500dd0a4..e552f895fa8 100644 --- a/tests/admin-ui-tests/CHANGELOG.md +++ b/tests/admin-ui-tests/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/admin-ui-tests +## 0.0.4 + +### Patch Changes + +- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/types@24.0.0 + - @keystone-next/testing@1.1.1 + - @keystone-next/utils@1.0.4 + ## 0.0.3 ### Patch Changes diff --git a/tests/admin-ui-tests/package.json b/tests/admin-ui-tests/package.json index 81d9992dab8..c59a07e04fe 100644 --- a/tests/admin-ui-tests/package.json +++ b/tests/admin-ui-tests/package.json @@ -2,7 +2,7 @@ "name": "@keystone-next/admin-ui-tests", "description": "A set of tests for the KeystoneJS Admin UI.", "private": true, - "version": "0.0.3", + "version": "0.0.4", "author": "The KeystoneJS Development Team", "license": "MIT", "engines": { @@ -16,7 +16,7 @@ "@keystone-next/keystone": "*", "execa": "^5.1.1", "express": "^4.17.1", - "playwright": "^1.13.1", + "playwright": "^1.14.0", "treekill": "^1.0.0" }, "scripts": { @@ -25,9 +25,9 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/testing": "^1.1.0", - "@keystone-next/types": "^23.0.0", - "@keystone-next/utils": "^1.0.3", + "@keystone-next/testing": "^1.1.1", + "@keystone-next/types": "^24.0.0", + "@keystone-next/utils": "^1.0.4", "@manypkg/find-root": "^1.1.0", "dotenv": "^10.0.0", "tree-kill": "^1.2.2" diff --git a/tests/api-tests/CHANGELOG.md b/tests/api-tests/CHANGELOG.md index f48751d233d..59cf2f73b16 100644 --- a/tests/api-tests/CHANGELOG.md +++ b/tests/api-tests/CHANGELOG.md @@ -1,5 +1,18 @@ # @keystonejs/api-tests +## 11.1.0 + +### Minor Changes + +- [#6276](https://github.com/keystonejs/keystone/pull/6276) [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb) Thanks [@gautamsi](https://github.com/gautamsi)! - Added option for `Bearer` token auth when using session. + +### Patch Changes + +- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/types@24.0.0 + - @keystone-next/testing@1.1.1 + - @keystone-next/utils@1.0.4 + ## 11.0.6 ### Patch Changes diff --git a/tests/api-tests/access-control/authed.test.ts b/tests/api-tests/access-control/authed.test.ts index 963c6e670e9..746bab83f25 100644 --- a/tests/api-tests/access-control/authed.test.ts +++ b/tests/api-tests/access-control/authed.test.ts @@ -22,7 +22,7 @@ const expectNoAccess = ( errors: readonly GraphQLError[] | undefined, name: N ) => { - expectAccessDenied(errors, [{ path: [name] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: [name] }]); expect(data?.[name]).toBe(null); }; @@ -158,7 +158,9 @@ describe('Authed', () => { expect(data).toEqual({ authenticatedItem: { id: user.id, yesRead: user.yesRead, noRead: null }, }); - expectAccessDenied(errors, [{ path: ['authenticatedItem', 'noRead'] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['authenticatedItem', 'noRead'] }, + ]); }); (['imperative', 'declarative'] as const).forEach(mode => { @@ -218,7 +220,7 @@ describe('Authed', () => { test(`multiple not existing: ${JSON.stringify(access)}`, async () => { const _items = await context.lists[listKey].findMany({ - where: { id_in: [FAKE_ID[provider], FAKE_ID_2[provider]] }, + where: { id: { in: [FAKE_ID[provider], FAKE_ID_2[provider]] } }, }); expect(_items).toHaveLength(0); }); @@ -442,7 +444,7 @@ describe('Authed', () => { if (mode === 'imperative') { expectNamedArray(data, errors, multiDeleteMutationName, [validId1, validId2]); } else { - expectAccessDenied(errors, [ + expectAccessDenied('dev', false, undefined, errors, [ { path: [multiDeleteMutationName, 0] }, { path: [multiDeleteMutationName, 1] }, ]); @@ -459,7 +461,9 @@ describe('Authed', () => { if (mode === 'imperative') { expectNamedArray(data, errors, multiDeleteMutationName, [validId1, invalidId]); } else { - expectAccessDenied(errors, [{ path: [multiDeleteMutationName, 1] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: [multiDeleteMutationName, 1] }, + ]); expect(data).toEqual({ [multiDeleteMutationName]: [{ id: validId1 }, null] }); } }); @@ -468,7 +472,7 @@ describe('Authed', () => { const multiDeleteMutationName = `delete${nameFn[mode](access)}s`; const query = `mutation { ${multiDeleteMutationName}(where: [{ id: "${FAKE_ID[provider]}" }, { id: "${FAKE_ID_2[provider]}" }]) { id } }`; const { data, errors } = await context.graphql.raw({ query }); - expectAccessDenied(errors, [ + expectAccessDenied('dev', false, undefined, errors, [ { path: [multiDeleteMutationName, 0] }, { path: [multiDeleteMutationName, 1] }, ]); diff --git a/tests/api-tests/access-control/mutations-field-static.test.ts b/tests/api-tests/access-control/mutations-field-static.test.ts index 5ce3f47daca..7eebb4e8b4e 100644 --- a/tests/api-tests/access-control/mutations-field-static.test.ts +++ b/tests/api-tests/access-control/mutations-field-static.test.ts @@ -51,7 +51,7 @@ describe('Access control - Imperative => static', () => { // Returns null and throws an error expect(data).toEqual({ createUser: null }); - expectAccessDenied(errors, [{ path: ['createUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['createUser'] }]); // Only the original user should exist const _users = await context.lists.User.findMany({ query: 'id name other' }); @@ -79,7 +79,7 @@ describe('Access control - Imperative => static', () => { // Returns null and throws an error expect(data).toEqual({ updateUser: null }); - expectAccessDenied(errors, [{ path: ['updateUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['updateUser'] }]); // User should have its original name const _users = await context.lists.User.findMany({ query: 'id name other' }); @@ -118,7 +118,10 @@ describe('Access control - Imperative => static', () => { }); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied(errors, [{ path: ['createUsers', 1] }, { path: ['createUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['createUsers', 1] }, + { path: ['createUsers', 3] }, + ]); // Valid users should exist in the database const users = await context.lists.User.findMany({ @@ -172,7 +175,10 @@ describe('Access control - Imperative => static', () => { }); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied(errors, [{ path: ['updateUsers', 1] }, { path: ['updateUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['updateUsers', 1] }, + { path: ['updateUsers', 3] }, + ]); // All users should still exist in the database const _users = await context.lists.User.findMany({ diff --git a/tests/api-tests/access-control/mutations-list-declarative.test.ts b/tests/api-tests/access-control/mutations-list-declarative.test.ts index cbe015f6a77..c1618c85856 100644 --- a/tests/api-tests/access-control/mutations-list-declarative.test.ts +++ b/tests/api-tests/access-control/mutations-list-declarative.test.ts @@ -12,8 +12,8 @@ const runner = setupTestRunner({ access: { read: true, create: true, - update: () => ({ name_not: 'bad' }), - delete: async () => ({ name_not_contains: 'no delete' }), + update: () => ({ name: { not: { equals: 'bad' } } }), + delete: async () => ({ name: { not: { contains: 'no delete' } } }), }, }), }), @@ -40,7 +40,7 @@ describe('Access control - Imperative => declarative', () => { // Returns null and throws an error expect(data).toEqual({ updateUser: null }); - expectAccessDenied(errors, [{ path: ['updateUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['updateUser'] }]); // User should have its original name const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -65,7 +65,7 @@ describe('Access control - Imperative => declarative', () => { // Returns null and throws an error expect(data).toEqual({ deleteUser: null }); - expectAccessDenied(errors, [{ path: ['deleteUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['deleteUser'] }]); // Bad users should still be in the database. const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -120,7 +120,10 @@ describe('Access control - Imperative => declarative', () => { null, ], }); - expectAccessDenied(errors, [{ path: ['updateUsers', 1] }, { path: ['updateUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['updateUsers', 1] }, + { path: ['updateUsers', 3] }, + ]); // All users should still exist in the database const _users = await context.lists.User.findMany({ @@ -161,7 +164,10 @@ describe('Access control - Imperative => declarative', () => { }, }); - expectAccessDenied(errors, [{ path: ['deleteUsers', 1] }, { path: ['deleteUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['deleteUsers', 1] }, + { path: ['deleteUsers', 3] }, + ]); // Valid users are returned, invalid come back as null // The invalid deletes should have errors which point to the nulls in their path diff --git a/tests/api-tests/access-control/mutations-list-static.test.ts b/tests/api-tests/access-control/mutations-list-static.test.ts index 3984c0c9e6f..3c2ce0d1a0a 100644 --- a/tests/api-tests/access-control/mutations-list-static.test.ts +++ b/tests/api-tests/access-control/mutations-list-static.test.ts @@ -46,7 +46,7 @@ describe('Access control - Imperative => static', () => { // Returns null and throws an error expect(data).toEqual({ createUser: null }); - expectAccessDenied(errors, [{ path: ['createUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['createUser'] }]); // Only the original user should exist const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -70,7 +70,7 @@ describe('Access control - Imperative => static', () => { // Returns null and throws an error expect(data).toEqual({ updateUser: null }); - expectAccessDenied(errors, [{ path: ['updateUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['updateUser'] }]); // User should have its original name const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -95,7 +95,7 @@ describe('Access control - Imperative => static', () => { // Returns null and throws an error expect(data).toEqual({ deleteUser: null }); - expectAccessDenied(errors, [{ path: ['deleteUser'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['deleteUser'] }]); // Bad users should still be in the database. const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -133,7 +133,10 @@ describe('Access control - Imperative => static', () => { }); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied(errors, [{ path: ['createUsers', 1] }, { path: ['createUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['createUsers', 1] }, + { path: ['createUsers', 3] }, + ]); // The good users should exist in the database const users = await context.lists.User.findMany(); @@ -182,7 +185,10 @@ describe('Access control - Imperative => static', () => { ]); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied(errors, [{ path: ['updateUsers', 1] }, { path: ['updateUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['updateUsers', 1] }, + { path: ['updateUsers', 3] }, + ]); // All users should still exist in the database const _users = await context.lists.User.findMany({ @@ -232,7 +238,10 @@ describe('Access control - Imperative => static', () => { ]); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied(errors, [{ path: ['deleteUsers', 1] }, { path: ['deleteUsers', 3] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['deleteUsers', 1] }, + { path: ['deleteUsers', 3] }, + ]); const _users = await context.lists.User.findMany({ orderBy: { name: 'asc' }, diff --git a/tests/api-tests/access-control/not-authed.test.ts b/tests/api-tests/access-control/not-authed.test.ts index 2ac02923d9d..d95b7f3f4f8 100644 --- a/tests/api-tests/access-control/not-authed.test.ts +++ b/tests/api-tests/access-control/not-authed.test.ts @@ -20,7 +20,7 @@ const expectNoAccess = ( name: N ) => { expect(data?.[name]).toBe(null); - expectAccessDenied(errors, [{ path: [name] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: [name] }]); }; type IdType = any; @@ -136,7 +136,7 @@ describe(`Not authed`, () => { const query = `mutation { ${createMutationName}(data: { ${fieldName}: "bar" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); expect(data).toEqual({ [createMutationName]: null }); - expectAccessDenied(errors, [{ path: [createMutationName] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: [createMutationName] }]); }); }); }); @@ -163,7 +163,7 @@ describe(`Not authed`, () => { const query = `query { ${countName} }`; const { data, errors } = await context.graphql.raw({ query }); expect(data).toEqual({ [countName]: null }); - expectAccessDenied(errors, [{ path: [countName] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: [countName] }]); }); test(`single denied: ${JSON.stringify(access)}`, async () => { @@ -197,7 +197,9 @@ describe(`Not authed`, () => { }); const query = `query { ${singleQueryName}(where: { id: "${item.id}" }) { id ${fieldName} } }`; const { data, errors } = await context.graphql.raw({ query }); - expectAccessDenied(errors, [{ path: [singleQueryName, fieldName] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: [singleQueryName, fieldName] }, + ]); expect(data).toEqual({ [singleQueryName]: { id: item.id, [fieldName]: null } }); }); test(`field allowed - multi: ${JSON.stringify(access)}`, async () => { @@ -217,7 +219,7 @@ describe(`Not authed`, () => { }); const query = `query { ${allQueryName} { id ${fieldName} } }`; const { data, errors } = await context.graphql.raw({ query }); - expectAccessDenied(errors, [ + expectAccessDenied('dev', false, undefined, errors, [ { path: [allQueryName, 0, fieldName] }, { path: [allQueryName, 1, fieldName] }, ]); @@ -351,7 +353,7 @@ describe(`Not authed`, () => { const query = `mutation { ${updateMutationName}(where: { id: "${item.id}" }, data: { ${fieldName}: "bar" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); expect(data).toEqual({ [updateMutationName]: null }); - expectAccessDenied(errors, [{ path: [updateMutationName] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: [updateMutationName] }]); }); }); }); @@ -377,7 +379,9 @@ describe(`Not authed`, () => { const { data, errors } = await context.graphql.raw({ query }); expect(data).toEqual({ [multiDeleteMutationName]: [null] }); - expectAccessDenied(errors, [{ path: [multiDeleteMutationName, 0] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: [multiDeleteMutationName, 0] }, + ]); }); }); }); diff --git a/tests/api-tests/access-control/utils.ts b/tests/api-tests/access-control/utils.ts index 012a038f17c..f8ad58fb1db 100644 --- a/tests/api-tests/access-control/utils.ts +++ b/tests/api-tests/access-control/utils.ts @@ -38,7 +38,7 @@ const getDeclarativeListName = (access: BooleanAccess) => `${getPrefix(access)}D }), {})); } */ -const listAccessVariations: BooleanAccess[] = [ +const listAccessVariations: (BooleanAccess & { delete: boolean })[] = [ { create: false, read: false, update: false, delete: false }, { create: true, read: false, update: false, delete: false }, { create: false, read: true, update: false, delete: false }, @@ -129,9 +129,9 @@ listAccessVariations.forEach(access => { access: { create: access.create, // arbitrarily restrict the data to a single item (see data.js) - read: () => access.read && { name: 'Hello' }, - update: () => access.update && { name: 'Hello' }, - delete: () => access.delete && { name: 'Hello' }, + read: () => access.read && { name: { equals: 'Hello' } }, + update: () => access.update && { name: { equals: 'Hello' } }, + delete: () => access.delete && { name: { equals: 'Hello' } }, }, }); }); diff --git a/tests/api-tests/auth-header.test.ts b/tests/api-tests/auth-header.test.ts index c64eeda9a61..e9d027d55d3 100644 --- a/tests/api-tests/auth-header.test.ts +++ b/tests/api-tests/auth-header.test.ts @@ -83,7 +83,7 @@ describe('Auth testing', () => { } const { data, errors } = await context.graphql.raw({ query: '{ users { id } }' }); expect(data).toEqual({ users: null }); - expectAccessDenied(errors, [{ path: ['users'] }]); + expectAccessDenied('dev', false, undefined, errors, [{ path: ['users'] }]); }) ); @@ -118,8 +118,7 @@ describe('Auth testing', () => { }); describe('logged in', () => { - // eslint-disable-next-line jest/no-disabled-tests - test.skip( + test( 'Allows access with bearer token', runner(async ({ context, graphQLRequest }) => { for (const [listKey, data] of Object.entries(initialData)) { diff --git a/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts b/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts index c14587da68a..5d07a5b50a9 100644 --- a/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts +++ b/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts @@ -70,13 +70,15 @@ describe('extendGraphqlSchema', () => { runner(async ({ graphQLRequest }) => { const { body } = await graphQLRequest({ query: ` - query { - quads(x: 10) - } - `, + query { + quads(x: 10) + } + `, }); expect(body.data).toEqual({ quads: null }); - expectInternalServerError(body.errors, [{ path: ['quads'], message: 'Access denied' }]); + expectInternalServerError(body.errors, false, [ + { path: ['quads'], message: 'Access denied' }, + ]); }) ); it( diff --git a/tests/api-tests/fields/filter.test.ts b/tests/api-tests/fields/filter.test.ts index 96da9dd5ba6..21d803ed0c5 100644 --- a/tests/api-tests/fields/filter.test.ts +++ b/tests/api-tests/fields/filter.test.ts @@ -93,289 +93,357 @@ testModules ? `name ${fieldName} { ${subfieldName} }` : `name ${fieldName}`; - const match = async ( - context: KeystoneContext, - where: Record | undefined, - expected: any[], - orderBy: Record = { name: 'asc' } - ) => - expect(await context.lists[listKey].findMany({ where, orderBy, query })).toEqual( - expected.map(i => storedValues[i]) - ); + describe.each(['without negation', 'with negation'] as const)('%s', kind => { + const match = async ( + context: KeystoneContext, + where: Record | undefined, + expectedIndexes: number[] + ) => { + let expected = expectedIndexes.map(i => storedValues[i]); + if (kind === 'with negation') { + const expectedWithoutNegation = new Set(expected); + expected = storedValues.filter((v: any) => !expectedWithoutNegation.has(v)); + } + expect( + await context.lists[listKey].findMany({ + where: kind === 'with negation' ? { NOT: where } : where, + orderBy: { name: 'asc' }, + query, + }) + ).toEqual(expected); + }; - test( - `No Filter`, - withKeystone(({ context }) => match(context, undefined, [0, 1, 2, 3, 4, 5, 6])) - ); + if (kind === 'without negation') { + test( + `No Filter`, + withKeystone(({ context }) => match(context, undefined, [0, 1, 2, 3, 4, 5, 6])) + ); + // arguably this should return [] when negated + // but i assume prisma is like "this things empty, let's just ignore it" + // this is fine imo since "i want to query this api and have it definitely return no results" + // isn't really very useful + test( + `Empty Filter`, + withKeystone(({ context }) => match(context, {}, [0, 1, 2, 3, 4, 5, 6])) + ); + } - test( - `Empty Filter`, - withKeystone(({ context }) => match(context, {}, [0, 1, 2, 3, 4, 5, 6])) - ); - if (mod.supportedFilters(provider).includes('null_equality')) { - test( - 'Equals null', - withKeystone(({ context }) => match(context, { [`${fieldName}`]: null }, [5, 6])) - ); - test( - 'Not Equals null', - withKeystone(({ context }) => - match(context, { [`${fieldName}_not`]: null }, [0, 1, 2, 3, 4]) - ) - ); - } - if (mod.supportedFilters(provider).includes('equality')) { - test( - 'Equals', - withKeystone(({ context }) => - match(context, { [`${fieldName}`]: storedValues[3][fieldName] }, [3]) - ) - ); - test( - 'Not Equals', - withKeystone(({ context }) => - match( - context, - { [`${fieldName}_not`]: storedValues[3][fieldName] }, - [0, 1, 2, 4, 5, 6] + if (mod.supportedFilters(provider).includes('null_equality')) { + test( + 'Equals null', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { equals: null } }, [5, 6]) ) - ) - ); - } - if (mod.supportedFilters(provider).includes('equality_case_insensitive')) { - test( - `Equals - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_i`]: storedValues[3][fieldName] }, [2, 3, 4]) - ) - ); - - test( - `Not Equals - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_i`]: storedValues[3][fieldName] }, [0, 1, 5, 6]) - ) - ); - } - if (mod.supportedFilters(provider).includes('string')) { - test( - `Contains`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_contains`]: 'oo' }, [3, 4]) - ) - ); - test( - `Not Contains`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_contains`]: 'oo' }, [0, 1, 2, 5, 6]) - ) - ); - test( - `Starts With`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_starts_with`]: 'foo' }, [3, 4]) - ) - ); - test( - `Not Starts With`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_starts_with`]: 'foo' }, [0, 1, 2, 5, 6]) - ) - ); - test( - `Ends With`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_ends_with`]: 'BAR' }, [2, 3]) - ) - ); - test( - `Not Ends With`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_ends_with`]: 'BAR' }, [0, 1, 4, 5, 6]) - ) - ); - } - if (mod.supportedFilters(provider).includes('string_case_insensitive')) { - test( - `Contains - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_contains_i`]: 'oo' }, [2, 3, 4]) - ) - ); - - test( - `Not Contains - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_contains_i`]: 'oo' }, [0, 1, 5, 6]) - ) - ); + ); + test( + 'Not Equals null', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { not: { equals: null } } }, [0, 1, 2, 3, 4]) + ) + ); + } + if (mod.supportedFilters(provider).includes('equality')) { + test( + 'Equals', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { equals: storedValues[3][fieldName] } }, [3]) + ) + ); + test( + 'Not Equals', + withKeystone(({ context }) => + match( + context, + { NOT: { [`${fieldName}`]: { equals: storedValues[3][fieldName] } } }, + [0, 1, 2, 4, 5, 6] + ) + ) + ); + } + if (mod.supportedFilters(provider).includes('equality_case_insensitive')) { + test( + `Equals - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { + [`${fieldName}`]: { equals: storedValues[3][fieldName], mode: 'insensitive' }, + }, + [2, 3, 4] + ) + ) + ); - test( - `Starts With - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_starts_with_i`]: 'foo' }, [2, 3, 4]) - ) - ); + test( + `Not Equals - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { + [`${fieldName}`]: { + mode: 'insensitive', + not: { equals: storedValues[3][fieldName] }, + }, + }, + [0, 1, 5, 6] + ) + ) + ); + } + if (mod.supportedFilters(provider).includes('string')) { + test( + `Contains`, + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { contains: 'oo' } }, [3, 4]) + ) + ); + test( + `Not Contains`, + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { not: { contains: 'oo' } } }, [0, 1, 2, 5, 6]) + ) + ); + test( + `Starts With`, + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { startsWith: 'foo' } }, [3, 4]) + ) + ); + test( + `Not Starts With`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { not: { startsWith: 'foo' } } }, + [0, 1, 2, 5, 6] + ) + ) + ); + test( + `Ends With`, + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { endsWith: 'BAR' } }, [2, 3]) + ) + ); + test( + `Not Ends With`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { not: { endsWith: 'BAR' } } }, + [0, 1, 4, 5, 6] + ) + ) + ); + } + if (mod.supportedFilters(provider).includes('string_case_insensitive')) { + test( + `Contains - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { mode: 'insensitive', contains: 'oo' } }, + [2, 3, 4] + ) + ) + ); - test( - `Not Starts With - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_starts_with_i`]: 'foo' }, [0, 1, 5, 6]) - ) - ); + test( + `Not Contains - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { mode: 'insensitive', not: { contains: 'oo' } } }, + [0, 1, 5, 6] + ) + ) + ); - test( - `Ends With - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_ends_with_i`]: 'BAR' }, [2, 3, 4]) - ) - ); + test( + `Starts With - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { mode: 'insensitive', startsWith: 'foo' } }, + [2, 3, 4] + ) + ) + ); - test( - `Not Ends With - Case Insensitive`, - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_ends_with_i`]: 'BAR' }, [0, 1, 5, 6]) - ) - ); - } - if (mod.supportedFilters(provider).includes('ordering')) { - test( - 'Less than', - withKeystone(({ context }) => - match(context, { [`${fieldName}_lt`]: storedValues[2][fieldName] }, [0, 1]) - ) - ); - test( - 'Less than or equal', - withKeystone(({ context }) => - match(context, { [`${fieldName}_lte`]: storedValues[2][fieldName] }, [0, 1, 2]) - ) - ); - test( - 'Greater than', - withKeystone(({ context }) => - match(context, { [`${fieldName}_gt`]: storedValues[2][fieldName] }, [3, 4]) - ) - ); - test( - 'Greater than or equal', - withKeystone(({ context }) => - match(context, { [`${fieldName}_gte`]: storedValues[2][fieldName] }, [2, 3, 4]) - ) - ); - } - if (mod.supportedFilters(provider).includes('in_empty_null')) { - test( - 'In - Empty List', - withKeystone(({ context }) => match(context, { [`${fieldName}_in`]: [] }, [])) - ); + test( + `Not Starts With - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { mode: 'insensitive', not: { startsWith: 'foo' } } }, + [0, 1, 5, 6] + ) + ) + ); - test( - 'Not In - Empty List', - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_in`]: [] }, [0, 1, 2, 3, 4, 5, 6]) - ) - ); + test( + `Ends With - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { mode: 'insensitive', endsWith: 'BAR' } }, + [2, 3, 4] + ) + ) + ); - test( - 'In - null', - withKeystone(({ context }) => match(context, { [`${fieldName}_in`]: [null] }, [5, 6])) - ); + test( + `Not Ends With - Case Insensitive`, + withKeystone(({ context }) => + match( + context, + { + [`${fieldName}`]: { mode: 'insensitive', not: { endsWith: 'BAR' } }, + }, + [0, 1, 5, 6] + ) + ) + ); + } + if (mod.supportedFilters(provider).includes('ordering')) { + test( + 'Less than', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { lt: storedValues[2][fieldName] } }, [0, 1]) + ) + ); + test( + 'Less than or equal', + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { lte: storedValues[2][fieldName] } }, + [0, 1, 2] + ) + ) + ); + test( + 'Greater than', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { gt: storedValues[2][fieldName] } }, [3, 4]) + ) + ); + test( + 'Greater than or equal', + withKeystone(({ context }) => + match( + context, + { [`${fieldName}`]: { gte: storedValues[2][fieldName] } }, + [2, 3, 4] + ) + ) + ); + } + if (mod.supportedFilters(provider).includes('in_empty_null')) { + test( + 'In - Empty List', + withKeystone(({ context }) => match(context, { [`${fieldName}`]: { in: [] } }, [])) + ); - test( - 'Not In - null', - withKeystone(({ context }) => - match(context, { [`${fieldName}_not_in`]: [null] }, [0, 1, 2, 3, 4]) - ) - ); - } - if (mod.supportedFilters(provider).includes('in_equal')) { - test( - 'In - values', - withKeystone(({ context }) => - match( - context, - { - [`${fieldName}_in`]: [ - storedValues[0][fieldName], - storedValues[2][fieldName], - storedValues[4][fieldName], - ], - }, - [0, 2, 4] + test( + 'Not In - Empty List', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { notIn: [] } }, [0, 1, 2, 3, 4, 5, 6]) ) - ) - ); - test( - 'Not In - values', - withKeystone(({ context }) => - match( - context, - { - [`${fieldName}_not_in`]: [ - storedValues[0][fieldName], - storedValues[2][fieldName], - storedValues[4][fieldName], - ], - }, - [1, 3, 5, 6] + ); + } + if (mod.supportedFilters(provider).includes('in_equal')) { + test( + 'In - values', + withKeystone(({ context }) => + match( + context, + { + [`${fieldName}`]: { + in: [ + storedValues[0][fieldName], + storedValues[2][fieldName], + storedValues[4][fieldName], + ], + }, + }, + [0, 2, 4] + ) ) - ) - ); - } - if (mod.supportedFilters(provider).includes('is_set')) { - test( - 'Is Set - true', - withKeystone(({ context }) => - match(context, { [`${fieldName}_is_set`]: true }, [0, 2, 3, 4]) - ) - ); - test( - 'Is Set - false', - withKeystone(({ context }) => - match(context, { [`${fieldName}_is_set`]: false }, [1, 5, 6]) - ) - ); - } - if (mod.supportedFilters(provider).includes('unique_equality')) { - test( - 'Unique equality', - setupTestRunner({ - config: apiTestConfig({ - lists: createSchema({ - [listKey]: list({ - fields: { - field: mod.typeFunction({ isUnique: true }), + ); + test( + 'Not In - values', + withKeystone(({ context }) => + match( + context, + { + [`${fieldName}`]: { + notIn: [ + storedValues[0][fieldName], + storedValues[2][fieldName], + storedValues[4][fieldName], + ], }, + }, + [1, 3, 5, 6] + ) + ) + ); + } + if (mod.supportedFilters(provider).includes('is_set')) { + test( + 'Is Set - true', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { isSet: true } }, [0, 2, 3, 4]) + ) + ); + test( + 'Is Set - false', + withKeystone(({ context }) => + match(context, { [`${fieldName}`]: { isSet: false } }, [1, 5, 6]) + ) + ); + } + if (mod.supportedFilters(provider).includes('unique_equality')) { + test( + 'Unique equality', + setupTestRunner({ + config: apiTestConfig({ + lists: createSchema({ + [listKey]: list({ + fields: { + field: mod.typeFunction({ isUnique: true }), + }, + }), }), }), - }), - })(async ({ context }) => { - // Populate the database before running the tests - // Note: this seeding has to be in an order defined by the array returned by `mod.initItems()` - for (const data of mod.initItems(matrixValue)) { - await context.lists[listKey].createOne({ - data: { field: data[fieldName] }, - }); - } - await Promise.all( - storedValues.map(async (val: any) => { - const promise = context.lists[listKey].findOne({ - where: { field: val[fieldName] }, - query: 'field', + })(async ({ context }) => { + // Populate the database before running the tests + // Note: this seeding has to be in an order defined by the array returned by `mod.initItems()` + for (const data of mod.initItems(matrixValue)) { + await context.lists[listKey].createOne({ + data: { field: data[fieldName] }, }); - if (val[fieldName] === null) { - expect(await promise.catch(x => x.toString())).toMatch( - 'The unique value provided in a unique where input must not be null' - ); - } else { - expect(await promise).toEqual({ field: val[fieldName] }); - } - }) - ); - }) - ); - } + } + await Promise.all( + storedValues.map(async (val: any) => { + const promise = context.lists[listKey].findOne({ + where: { field: val[fieldName] }, + query: 'field', + }); + if (val[fieldName] === null) { + expect(await promise.catch(x => x.toString())).toMatch( + 'The unique value provided in a unique where input must not be null' + ); + } else { + expect(await promise).toEqual({ field: val[fieldName] }); + } + }) + ); + }) + ); + } + }); }); } }); diff --git a/tests/api-tests/fields/types/Virtual.test.ts b/tests/api-tests/fields/types/Virtual.test.ts index 93e0093274d..1c06f1b9de6 100644 --- a/tests/api-tests/fields/types/Virtual.test.ts +++ b/tests/api-tests/fields/types/Virtual.test.ts @@ -118,10 +118,14 @@ describe('Virtual field type', () => { async resolve(rootVal, args, context) { const [personAuthors, organisationAuthors] = await Promise.all([ context.db.lists.Person.findMany({ - where: { authoredPosts_some: { id: rootVal.id.toString() } }, + where: { + authoredPosts: { some: { id: { equals: rootVal.id.toString() } } }, + }, }), context.db.lists.Organisation.findMany({ - where: { authoredPosts_some: { id: rootVal.id.toString() } }, + where: { + authoredPosts: { some: { id: { equals: rootVal.id.toString() } } }, + }, }), ]); if (personAuthors.length) { diff --git a/tests/api-tests/fields/types/document.test.ts b/tests/api-tests/fields/types/document.test.ts index c3df3699ba4..8609c0ca211 100644 --- a/tests/api-tests/fields/types/document.test.ts +++ b/tests/api-tests/fields/types/document.test.ts @@ -46,7 +46,7 @@ const runner = setupTestRunner({ }, }), }, - access: { read: { name_not: 'Charlie' } }, + access: { read: { name: { not: { equals: 'Charlie' } } } }, }), }), }), @@ -284,7 +284,7 @@ describe('Document field type', () => { }); // FIXME: The path doesn't match the null field here! expect(body.data).toEqual({ author: { badBio: null } }); - expectInternalServerError(body.errors, [ + expectInternalServerError(body.errors, true, [ { path: ['author', 'badBio', 'document'], message: 'Cannot query field "bad" on type "Author". Did you mean "bio" or "id"?', diff --git a/tests/api-tests/fields/unique.test.ts b/tests/api-tests/fields/unique.test.ts index 8b656ecf57a..b2bf558bb4c 100644 --- a/tests/api-tests/fields/unique.test.ts +++ b/tests/api-tests/fields/unique.test.ts @@ -76,6 +76,8 @@ testModules message: expect.stringMatching( /\nInvalid `prisma\.test\.create\(\)` invocation:\n(.*\n){2} Unique constraint failed on the fields: \(`testField`\)/ ), + code: 'P2002', + target: ['testField'], }, ]); }) @@ -104,6 +106,8 @@ testModules message: expect.stringMatching( /\nInvalid `prisma\.test\.create\(\)` invocation:\n(.*\n){2} Unique constraint failed on the fields: \(`testField`\)/ ), + code: 'P2002', + target: ['testField'], }, ]); }) diff --git a/tests/api-tests/hooks/hook-errors.test.ts b/tests/api-tests/hooks/hook-errors.test.ts index fd9938f5f64..bd2dad79fab 100644 --- a/tests/api-tests/hooks/hook-errors.test.ts +++ b/tests/api-tests/hooks/hook-errors.test.ts @@ -1,407 +1,574 @@ import { text } from '@keystone-next/fields'; import { createSchema, list } from '@keystone-next/keystone/schema'; -import { setupTestRunner } from '@keystone-next/testing'; +import { GraphQLRequest, setupTestRunner } from '@keystone-next/testing'; +import { KeystoneContext } from '../../../packages/types/src'; import { apiTestConfig, expectAccessDenied, expectExtensionError } from '../utils'; -const runner = setupTestRunner({ - config: apiTestConfig({ - lists: createSchema({ - User: list({ - fields: { name: text() }, - hooks: { - beforeChange: ({ resolvedData }) => { - if (resolvedData.name === 'trigger before') { - throw new Error('Simulated error: beforeChange'); - } - }, - afterChange: ({ resolvedData }) => { - if (resolvedData.name === 'trigger after') { - throw new Error('Simulated error: afterChange'); - } - }, - beforeDelete: ({ existingItem }) => { - if (existingItem.name === 'trigger before delete') { - throw new Error('Simulated error: beforeDelete'); - } - }, - afterDelete: ({ existingItem }) => { - if (existingItem.name === 'trigger after delete') { - throw new Error('Simulated error: afterDelete'); - } - }, - }, - }), - Post: list({ - fields: { - title: text({ - hooks: { - beforeChange: ({ resolvedData }) => { - if (resolvedData.title === 'trigger before') { - throw new Error('Simulated error: title: beforeChange'); - } - }, - afterChange: ({ resolvedData }) => { - if (resolvedData.title === 'trigger after') { - throw new Error('Simulated error: title: afterChange'); - } - }, - beforeDelete: ({ existingItem }) => { - if (existingItem.title === 'trigger before delete') { - throw new Error('Simulated error: title: beforeDelete'); - } - }, - afterDelete: ({ existingItem }) => { - if (existingItem.title === 'trigger after delete') { - throw new Error('Simulated error: title: afterDelete'); - } - }, +const runner = (debug: boolean | undefined) => + setupTestRunner({ + config: apiTestConfig({ + lists: createSchema({ + User: list({ + fields: { name: text() }, + hooks: { + beforeChange: ({ resolvedData }) => { + if (resolvedData.name === 'trigger before') { + throw new Error('Simulated error: beforeChange'); + } }, - }), - content: text({ - hooks: { - beforeChange: ({ resolvedData }) => { - if (resolvedData.content === 'trigger before') { - throw new Error('Simulated error: content: beforeChange'); - } - }, - afterChange: ({ resolvedData }) => { - if (resolvedData.content === 'trigger after') { - throw new Error('Simulated error: content: afterChange'); - } - }, - beforeDelete: ({ existingItem }) => { - if (existingItem.content === 'trigger before delete') { - throw new Error('Simulated error: content: beforeDelete'); - } + afterChange: ({ resolvedData }) => { + if (resolvedData.name === 'trigger after') { + throw new Error('Simulated error: afterChange'); + } + }, + beforeDelete: ({ existingItem }) => { + if (existingItem.name === 'trigger before delete') { + throw new Error('Simulated error: beforeDelete'); + } + }, + afterDelete: ({ existingItem }) => { + if (existingItem.name === 'trigger after delete') { + throw new Error('Simulated error: afterDelete'); + } + }, + }, + }), + Post: list({ + fields: { + title: text({ + hooks: { + beforeChange: ({ resolvedData }) => { + if (resolvedData.title === 'trigger before') { + throw new Error('Simulated error: title: beforeChange'); + } + }, + afterChange: ({ resolvedData }) => { + if (resolvedData.title === 'trigger after') { + throw new Error('Simulated error: title: afterChange'); + } + }, + beforeDelete: ({ existingItem }) => { + if (existingItem.title === 'trigger before delete') { + throw new Error('Simulated error: title: beforeDelete'); + } + }, + afterDelete: ({ existingItem }) => { + if (existingItem.title === 'trigger after delete') { + throw new Error('Simulated error: title: afterDelete'); + } + }, }, - afterDelete: ({ existingItem }) => { - if (existingItem.content === 'trigger after delete') { - throw new Error('Simulated error: content: afterDelete'); - } + }), + content: text({ + hooks: { + beforeChange: ({ resolvedData }) => { + if (resolvedData.content === 'trigger before') { + throw new Error('Simulated error: content: beforeChange'); + } + }, + afterChange: ({ resolvedData }) => { + if (resolvedData.content === 'trigger after') { + throw new Error('Simulated error: content: afterChange'); + } + }, + beforeDelete: ({ existingItem }) => { + if (existingItem.content === 'trigger before delete') { + throw new Error('Simulated error: content: beforeDelete'); + } + }, + afterDelete: ({ existingItem }) => { + if (existingItem.content === 'trigger after delete') { + throw new Error('Simulated error: content: afterDelete'); + } + }, }, - }, - }), - }, + }), + }, + }), }), + graphql: { debug }, }), - }), -}); + }); -['before', 'after'].map(phase => { - describe(`List Hooks: ${phase}Change/${phase}Delete()`, () => { - test( - 'createOne', - runner(async ({ context }) => { - // Valid name should pass - await context.lists.User.createOne({ data: { name: 'good' } }); +[true, false].map(useHttp => { + const runQuery = async ( + context: KeystoneContext, + graphQLRequest: GraphQLRequest, + query: { query: string; variables?: Record } + ) => { + if (useHttp) { + const { body } = await graphQLRequest(query); + return body; + } else { + return await context.graphql.raw(query); + } + }; - // Trigger an error - const { data, errors } = await context.graphql.raw({ - query: `mutation ($data: UserCreateInput!) { createUser(data: $data) { id } }`, - variables: { data: { name: `trigger ${phase}` } }, + [true, false, undefined].map(debug => { + (['dev', 'production'] as const).map(mode => + describe(`NODE_ENV=${mode}, debug=${debug} useHttp=${useHttp}`, () => { + beforeAll(() => { + // @ts-ignore + process.env.NODE_ENV = mode; + }); + afterAll(() => { + // @ts-ignore + process.env.NODE_ENV = 'test'; }); - // Returns null and throws an error - expect(data).toEqual({ createUser: null }); - expectExtensionError(errors, `${phase}Change`, [ - { path: ['createUser'], messages: [`User: Simulated error: ${phase}Change`] }, - ]); + ['before', 'after'].map(phase => { + describe(`List Hooks: ${phase}Change/${phase}Delete()`, () => { + test( + 'createOne', + runner(debug)(async ({ context, graphQLRequest }) => { + // Valid name should pass + await context.lists.User.createOne({ data: { name: 'good' } }); - // Only the original user should exist for 'before', both exist for 'after' - const _users = await context.lists.User.findMany({ query: 'id name' }); - expect(_users.map(({ name }) => name)).toEqual( - phase === 'before' ? ['good'] : ['good', 'trigger after'] - ); - }) - ); + // Trigger an error + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($data: UserCreateInput!) { createUser(data: $data) { id } }`, + variables: { data: { name: `trigger ${phase}` } }, + }); - test( - 'updateOne', - runner(async ({ context }) => { - // Valid name should pass - const user = await context.lists.User.createOne({ data: { name: 'good' } }); - await context.lists.User.updateOne({ where: { id: user.id }, data: { name: 'better' } }); + // Returns null and throws an error + expect(data).toEqual({ createUser: null }); + const message = `Simulated error: ${phase}Change`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Change`, [ + { + path: ['createUser'], + messages: [`User: Simulated error: ${phase}Change`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + ]); - // Invalid name - const { data, errors } = await context.graphql.raw({ - query: `mutation ($id: ID! $data: UserUpdateInput!) { updateUser(where: { id: $id }, data: $data) { id } }`, - variables: { id: user.id, data: { name: `trigger ${phase}` } }, - }); + // Only the original user should exist for 'before', both exist for 'after' + const _users = await context.lists.User.findMany({ query: 'id name' }); + expect(_users.map(({ name }) => name)).toEqual( + phase === 'before' ? ['good'] : ['good', 'trigger after'] + ); + }) + ); - // Returns null and throws an error - expect(data).toEqual({ updateUser: null }); - expectExtensionError(errors, `${phase}Change`, [ - { path: ['updateUser'], messages: [`User: Simulated error: ${phase}Change`] }, - ]); + test( + 'updateOne', + runner(debug)(async ({ context, graphQLRequest }) => { + // Valid name should pass + const user = await context.lists.User.createOne({ data: { name: 'good' } }); + await context.lists.User.updateOne({ + where: { id: user.id }, + data: { name: 'better' }, + }); - // User should have its original name for 'before', and the new name for 'after'. - const _users = await context.lists.User.findMany({ query: 'id name' }); - expect(_users.map(({ name }) => name)).toEqual( - phase === 'before' ? ['better'] : ['trigger after'] - ); - }) - ); + // Invalid name + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($id: ID! $data: UserUpdateInput!) { updateUser(where: { id: $id }, data: $data) { id } }`, + variables: { id: user.id, data: { name: `trigger ${phase}` } }, + }); - test( - 'deleteOne', - runner(async ({ context }) => { - // Valid names should pass - const user1 = await context.lists.User.createOne({ data: { name: 'good' } }); - const user2 = await context.lists.User.createOne({ - data: { name: `trigger ${phase} delete` }, - }); - await context.lists.User.deleteOne({ where: { id: user1.id } }); + // Returns null and throws an error + expect(data).toEqual({ updateUser: null }); + const message = `Simulated error: ${phase}Change`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Change`, [ + { + path: ['updateUser'], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + ]); - // Invalid name - const { data, errors } = await context.graphql.raw({ - query: `mutation ($id: ID!) { deleteUser(where: { id: $id }) { id } }`, - variables: { id: user2.id }, - }); + // User should have its original name for 'before', and the new name for 'after'. + const _users = await context.lists.User.findMany({ query: 'id name' }); + expect(_users.map(({ name }) => name)).toEqual( + phase === 'before' ? ['better'] : ['trigger after'] + ); + }) + ); - // Returns null and throws an error - expect(data).toEqual({ deleteUser: null }); - expectExtensionError(errors, `${phase}Delete`, [ - { path: ['deleteUser'], messages: [`User: Simulated error: ${phase}Delete`] }, - ]); + test( + 'deleteOne', + runner(debug)(async ({ context, graphQLRequest }) => { + // Valid names should pass + const user1 = await context.lists.User.createOne({ data: { name: 'good' } }); + const user2 = await context.lists.User.createOne({ + data: { name: `trigger ${phase} delete` }, + }); + await context.lists.User.deleteOne({ where: { id: user1.id } }); - // Bad users should still be in the database for 'before', deleted for 'after'. - const _users = await context.lists.User.findMany({ query: 'id name' }); - expect(_users.map(({ name }) => name)).toEqual( - phase === 'before' ? ['trigger before delete'] : [] - ); - }) - ); + // Invalid name + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($id: ID!) { deleteUser(where: { id: $id }) { id } }`, + variables: { id: user2.id }, + }); - test( - 'createMany', - runner(async ({ context }) => { - // Mix of good and bad names - const { data, errors } = await context.graphql.raw({ - query: `mutation ($data: [UserCreateInput!]!) { createUsers(data: $data) { id name } }`, - variables: { - data: [ - { name: 'good 1' }, - { name: `trigger ${phase}` }, - { name: 'good 2' }, - { name: `trigger ${phase}` }, - { name: 'good 3' }, - ], - }, - }); + // Returns null and throws an error + expect(data).toEqual({ deleteUser: null }); + const message = `Simulated error: ${phase}Delete`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Delete`, [ + { + path: ['deleteUser'], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Delete .${__filename}`) + ), + }, + ], + }, + ]); - // Valid users are returned, invalid come back as null - expect(data).toEqual({ - createUsers: [ - { id: expect.any(String), name: 'good 1' }, - null, - { id: expect.any(String), name: 'good 2' }, - null, - { id: expect.any(String), name: 'good 3' }, - ], - }); - // The invalid creates should have errors which point to the nulls in their path - expectExtensionError(errors, `${phase}Change`, [ - { path: ['createUsers', 1], messages: [`User: Simulated error: ${phase}Change`] }, - { path: ['createUsers', 3], messages: [`User: Simulated error: ${phase}Change`] }, - ]); + // Bad users should still be in the database for 'before', deleted for 'after'. + const _users = await context.lists.User.findMany({ query: 'id name' }); + expect(_users.map(({ name }) => name)).toEqual( + phase === 'before' ? ['trigger before delete'] : [] + ); + }) + ); - // Three users should exist in the database for 'before,' five for 'after'. - const users = await context.lists.User.findMany({ - orderBy: { name: 'asc' }, - query: 'id name', - }); - expect(users.map(({ name }) => name)).toEqual( - phase === 'before' - ? ['good 1', 'good 2', 'good 3'] - : ['good 1', 'good 2', 'good 3', 'trigger after', 'trigger after'] - ); - }) - ); + test( + 'createMany', + runner(debug)(async ({ context, graphQLRequest }) => { + // Mix of good and bad names + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($data: [UserCreateInput!]!) { createUsers(data: $data) { id name } }`, + variables: { + data: [ + { name: 'good 1' }, + { name: `trigger ${phase}` }, + { name: 'good 2' }, + { name: `trigger ${phase}` }, + { name: 'good 3' }, + ], + }, + }); - test( - 'updateMany', - runner(async ({ context }) => { - // Start with some users - const users = await context.lists.User.createMany({ - data: [ - { name: 'good 1' }, - { name: 'good 2' }, - { name: 'good 3' }, - { name: 'good 4' }, - { name: 'good 5' }, - ], - query: 'id name', - }); + // Valid users are returned, invalid come back as null + expect(data).toEqual({ + createUsers: [ + { id: expect.any(String), name: 'good 1' }, + null, + { id: expect.any(String), name: 'good 2' }, + null, + { id: expect.any(String), name: 'good 3' }, + ], + }); + // The invalid creates should have errors which point to the nulls in their path + const message = `Simulated error: ${phase}Change`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Change`, [ + { + path: ['createUsers', 1], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + { + path: ['createUsers', 3], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + ]); - // Mix of good and bad names - const { data, errors } = await context.graphql.raw({ - query: `mutation ($data: [UserUpdateArgs!]!) { updateUsers(data: $data) { id name } }`, - variables: { - data: [ - { where: { id: users[0].id }, data: { name: 'still good 1' } }, - { where: { id: users[1].id }, data: { name: `trigger ${phase}` } }, - { where: { id: users[2].id }, data: { name: 'still good 3' } }, - { where: { id: users[3].id }, data: { name: `trigger ${phase}` } }, - ], - }, - }); + // Three users should exist in the database for 'before,' five for 'after'. + const users = await context.lists.User.findMany({ + orderBy: { name: 'asc' }, + query: 'id name', + }); + expect(users.map(({ name }) => name)).toEqual( + phase === 'before' + ? ['good 1', 'good 2', 'good 3'] + : ['good 1', 'good 2', 'good 3', 'trigger after', 'trigger after'] + ); + }) + ); - // Valid users are returned, invalid come back as null - expect(data).toEqual({ - updateUsers: [ - { id: users[0].id, name: 'still good 1' }, - null, - { id: users[2].id, name: 'still good 3' }, - null, - ], - }); - // The invalid updates should have errors which point to the nulls in their path - expectExtensionError(errors, `${phase}Change`, [ - { path: ['updateUsers', 1], messages: [`User: Simulated error: ${phase}Change`] }, - { path: ['updateUsers', 3], messages: [`User: Simulated error: ${phase}Change`] }, - ]); + test( + 'updateMany', + runner(debug)(async ({ context, graphQLRequest }) => { + // Start with some users + const users = await context.lists.User.createMany({ + data: [ + { name: 'good 1' }, + { name: 'good 2' }, + { name: 'good 3' }, + { name: 'good 4' }, + { name: 'good 5' }, + ], + query: 'id name', + }); - // All users should still exist in the database, un-changed for `before`, changed for `after`. - const _users = await context.lists.User.findMany({ - orderBy: { name: 'asc' }, - query: 'id name', - }); - expect(_users.map(({ name }) => name)).toEqual( - phase === 'before' - ? ['good 2', 'good 4', 'good 5', 'still good 1', 'still good 3'] - : ['good 5', 'still good 1', 'still good 3', 'trigger after', 'trigger after'] - ); - }) - ); + // Mix of good and bad names + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($data: [UserUpdateArgs!]!) { updateUsers(data: $data) { id name } }`, + variables: { + data: [ + { where: { id: users[0].id }, data: { name: 'still good 1' } }, + { where: { id: users[1].id }, data: { name: `trigger ${phase}` } }, + { where: { id: users[2].id }, data: { name: 'still good 3' } }, + { where: { id: users[3].id }, data: { name: `trigger ${phase}` } }, + ], + }, + }); - test( - 'deleteMany', - runner(async ({ context }) => { - // Start with some users - const users = await context.lists.User.createMany({ - data: [ - { name: 'good 1' }, - { name: `trigger ${phase} delete` }, - { name: 'good 3' }, - { name: `trigger ${phase} delete` }, - { name: 'good 5' }, - ], - query: 'id name', - }); + // Valid users are returned, invalid come back as null + expect(data).toEqual({ + updateUsers: [ + { id: users[0].id, name: 'still good 1' }, + null, + { id: users[2].id, name: 'still good 3' }, + null, + ], + }); + // The invalid updates should have errors which point to the nulls in their path + const message = `Simulated error: ${phase}Change`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Change`, [ + { + path: ['updateUsers', 1], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + { + path: ['updateUsers', 3], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + ]); - // Mix of good and bad names - const { data, errors } = await context.graphql.raw({ - query: `mutation ($where: [UserWhereUniqueInput!]!) { deleteUsers(where: $where) { id name } }`, - variables: { - where: [users[0].id, users[1].id, users[2].id, users[3].id].map(id => ({ id })), - }, - }); + // All users should still exist in the database, un-changed for `before`, changed for `after`. + const _users = await context.lists.User.findMany({ + orderBy: { name: 'asc' }, + query: 'id name', + }); + expect(_users.map(({ name }) => name)).toEqual( + phase === 'before' + ? ['good 2', 'good 4', 'good 5', 'still good 1', 'still good 3'] + : ['good 5', 'still good 1', 'still good 3', 'trigger after', 'trigger after'] + ); + }) + ); - // Valid users are returned, invalid come back as null - expect(data).toEqual({ - deleteUsers: [ - { id: users[0].id, name: 'good 1' }, - null, - { id: users[2].id, name: 'good 3' }, - null, - ], - }); - // The invalid deletes should have errors which point to the nulls in their path - expectExtensionError(errors, `${phase}Delete`, [ - { path: ['deleteUsers', 1], messages: [`User: Simulated error: ${phase}Delete`] }, - { path: ['deleteUsers', 3], messages: [`User: Simulated error: ${phase}Delete`] }, - ]); + test( + 'deleteMany', + runner(debug)(async ({ context, graphQLRequest }) => { + // Start with some users + const users = await context.lists.User.createMany({ + data: [ + { name: 'good 1' }, + { name: `trigger ${phase} delete` }, + { name: 'good 3' }, + { name: `trigger ${phase} delete` }, + { name: 'good 5' }, + ], + query: 'id name', + }); - // Three users should still exist in the database for `before`, only 1 for `after`. - const _users = await context.lists.User.findMany({ - orderBy: { name: 'asc' }, - query: 'id name', - }); - expect(_users.map(({ name }) => name)).toEqual( - phase === 'before' - ? ['good 5', 'trigger before delete', 'trigger before delete'] - : ['good 5'] - ); - }) - ); - }); -}); + // Mix of good and bad names + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($where: [UserWhereUniqueInput!]!) { deleteUsers(where: $where) { id name } }`, + variables: { + where: [users[0].id, users[1].id, users[2].id, users[3].id].map(id => ({ id })), + }, + }); -['before', 'after'].map(phase => { - describe(`Field Hooks: ${phase}Change/${phase}Delete()`, () => { - test( - 'update', - runner(async ({ context }) => { - const post = await context.lists.Post.createOne({ - data: { title: 'original title', content: 'original content' }, - }); + // Valid users are returned, invalid come back as null + expect(data).toEqual({ + deleteUsers: [ + { id: users[0].id, name: 'good 1' }, + null, + { id: users[2].id, name: 'good 3' }, + null, + ], + }); + // The invalid deletes should have errors which point to the nulls in their path + const message = `Simulated error: ${phase}Delete`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Delete`, [ + { + path: ['deleteUsers', 1], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Delete .${__filename}`) + ), + }, + ], + }, + { + path: ['deleteUsers', 3], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*${phase}Delete .${__filename}`) + ), + }, + ], + }, + ]); - const { data, errors } = await context.graphql.raw({ - query: `mutation ($id: ID! $data: PostUpdateInput!) { updatePost(where: { id: $id }, data: $data) { id } }`, - variables: { - id: post.id, - data: { title: `trigger ${phase}`, content: `trigger ${phase}` }, - }, + // Three users should still exist in the database for `before`, only 1 for `after`. + const _users = await context.lists.User.findMany({ + orderBy: { name: 'asc' }, + query: 'id name', + }); + expect(_users.map(({ name }) => name)).toEqual( + phase === 'before' + ? ['good 5', 'trigger before delete', 'trigger before delete'] + : ['good 5'] + ); + }) + ); + }); }); - expectExtensionError(errors, `${phase}Change`, [ - { - path: ['updatePost'], - messages: [ - `Post.title: Simulated error: title: ${phase}Change`, - `Post.content: Simulated error: content: ${phase}Change`, - ], - }, - ]); - expect(data).toEqual({ updatePost: null }); - // Post should have its original data for 'before', and the new data for 'after'. - const _post = await context.lists.Post.findOne({ - where: { id: post.id }, - query: 'title content', - }); - expect(_post).toEqual( - phase === 'before' - ? { title: 'original title', content: 'original content' } - : { title: 'trigger after', content: 'trigger after' } - ); - }) - ); + ['before', 'after'].map(phase => { + describe(`Field Hooks: ${phase}Change/${phase}Delete()`, () => { + test( + 'update', + runner(debug)(async ({ context, graphQLRequest }) => { + const post = await context.lists.Post.createOne({ + data: { title: 'original title', content: 'original content' }, + }); - test( - 'delete', - runner(async ({ context }) => { - const post = await context.lists.Post.createOne({ - data: { title: `trigger ${phase} delete`, content: `trigger ${phase} delete` }, - }); - const { data, errors } = await context.graphql.raw({ - query: `mutation ($id: ID!) { deletePost(where: { id: $id }) { id } }`, - variables: { id: post.id }, - }); - expectExtensionError(errors, `${phase}Delete`, [ - { - path: ['deletePost'], - messages: [ - `Post.title: Simulated error: title: ${phase}Delete`, - `Post.content: Simulated error: content: ${phase}Delete`, - ], - }, - ]); - expect(data).toEqual({ deletePost: null }); + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($id: ID! $data: PostUpdateInput!) { updatePost(where: { id: $id }, data: $data) { id } }`, + variables: { + id: post.id, + data: { title: `trigger ${phase}`, content: `trigger ${phase}` }, + }, + }); + const message1 = `Simulated error: title: ${phase}Change`; + const message2 = `Simulated error: content: ${phase}Change`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Change`, [ + { + path: ['updatePost'], + messages: [`Post.title: ${message1}`, `Post.content: ${message2}`], + debug: [ + { + message: message1, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message1}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + { + message: message2, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message2}\n[^\n]*${phase}Change .${__filename}`) + ), + }, + ], + }, + ]); + expect(data).toEqual({ updatePost: null }); - // Post should have its original data for 'before', and not exist for 'after'. - const result = await context.graphql.raw({ - query: `query ($id: ID!) { post(where: { id: $id }) { title content} }`, - variables: { id: post.id }, - }); - if (phase === 'before') { - expect(result.errors).toBe(undefined); - expect(result.data).toEqual({ - post: { title: 'trigger before delete', content: 'trigger before delete' }, + // Post should have its original data for 'before', and the new data for 'after'. + const _post = await context.lists.Post.findOne({ + where: { id: post.id }, + query: 'title content', + }); + expect(_post).toEqual( + phase === 'before' + ? { title: 'original title', content: 'original content' } + : { title: 'trigger after', content: 'trigger after' } + ); + }) + ); + + test( + `delete`, + runner(debug)(async ({ context, graphQLRequest }) => { + const post = await context.lists.Post.createOne({ + data: { title: `trigger ${phase} delete`, content: `trigger ${phase} delete` }, + }); + const { data, errors } = await runQuery(context, graphQLRequest, { + query: `mutation ($id: ID!) { deletePost(where: { id: $id }) { id } }`, + variables: { id: post.id }, + }); + const message1 = `Simulated error: title: ${phase}Delete`; + const message2 = `Simulated error: content: ${phase}Delete`; + expectExtensionError(mode, useHttp, debug, errors, `${phase}Delete`, [ + { + path: ['deletePost'], + messages: [`Post.title: ${message1}`, `Post.content: ${message2}`], + debug: [ + { + message: message1, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message1}\n[^\n]*${phase}Delete .${__filename}`) + ), + }, + { + message: message2, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message2}\n[^\n]*${phase}Delete .${__filename}`) + ), + }, + ], + }, + ]); + expect(data).toEqual({ deletePost: null }); + + // Post should have its original data for 'before', and not exist for 'after'. + const result = await runQuery(context, graphQLRequest, { + query: `query ($id: ID!) { post(where: { id: $id }) { title content} }`, + variables: { id: post.id }, + }); + if (phase === 'before') { + expect(result.errors).toBe(undefined); + expect(result.data).toEqual({ + post: { title: 'trigger before delete', content: 'trigger before delete' }, + }); + } else { + expectAccessDenied(mode, useHttp, debug, result.errors, [{ path: ['post'] }]); + expect(result.data).toEqual({ post: null }); + } + }) + ); }); - } else { - expectAccessDenied(result.errors, [{ path: ['post'] }]); - expect(result.data).toEqual({ post: null }); - } + }); }) ); }); diff --git a/tests/api-tests/hooks/list-hooks.test.ts b/tests/api-tests/hooks/list-hooks.test.ts index e862804b491..72ab482736c 100644 --- a/tests/api-tests/hooks/list-hooks.test.ts +++ b/tests/api-tests/hooks/list-hooks.test.ts @@ -1,7 +1,7 @@ import { text } from '@keystone-next/fields'; import { createSchema, list } from '@keystone-next/keystone/schema'; import { setupTestRunner } from '@keystone-next/testing'; -import { apiTestConfig } from '../utils'; +import { apiTestConfig, expectExtensionError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -11,6 +11,10 @@ const runner = setupTestRunner({ name: text({ hooks: { resolveInput: ({ resolvedData }) => { + if (resolvedData.name === 'trigger field error') { + throw new Error('Field error triggered'); + } + return `${resolvedData.name}-field`; }, }, @@ -18,6 +22,9 @@ const runner = setupTestRunner({ }, hooks: { resolveInput: ({ resolvedData }) => { + if (resolvedData.name === 'trigger list error-field') { + throw new Error('List error triggered'); + } return { name: `${resolvedData.name}-list`, }; @@ -29,18 +36,70 @@ const runner = setupTestRunner({ }); describe('List Hooks: #resolveInput()', () => { - it( + test( 'resolves fields first, then passes them to the list', runner(async ({ context }) => { - const user = await context.lists.User.createOne({ - data: { name: 'jess' }, - query: 'name', - }); - + const user = await context.lists.User.createOne({ data: { name: 'jess' }, query: 'name' }); // Field should be executed first, appending `-field`, then the list // should be executed which appends `-list`, and finally that total // result should be stored. expect(user.name).toBe('jess-field-list'); }) ); + + test( + 'List error', + runner(async ({ context }) => { + // Trigger an error + const { data, errors } = await context.graphql.raw({ + query: `mutation ($data: UserCreateInput!) { createUser(data: $data) { id } }`, + variables: { data: { name: `trigger list error` } }, + }); + // Returns null and throws an error + expect(data).toEqual({ createUser: null }); + const message = `List error triggered`; + expectExtensionError('dev', false, undefined, errors, `resolveInput`, [ + { + path: ['createUser'], + messages: [`User: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*resolveInput .${__filename}`) + ), + }, + ], + }, + ]); + }) + ); + + test( + 'Field error', + runner(async ({ context }) => { + // Trigger an error + const { data, errors } = await context.graphql.raw({ + query: `mutation ($data: UserCreateInput!) { createUser(data: $data) { id } }`, + variables: { data: { name: `trigger field error` } }, + }); + // Returns null and throws an error + expect(data).toEqual({ createUser: null }); + const message = `Field error triggered`; + expectExtensionError('dev', false, undefined, errors, `resolveInput`, [ + { + path: ['createUser'], + messages: [`User.name: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`Error: ${message}\n[^\n]*resolveInput .${__filename}`) + ), + }, + ], + }, + ]); + }) + ); }); diff --git a/tests/api-tests/id-field.test.ts b/tests/api-tests/id-field.test.ts index bc5dc63b5ca..095be4f6000 100644 --- a/tests/api-tests/id-field.test.ts +++ b/tests/api-tests/id-field.test.ts @@ -35,7 +35,7 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { 'Filtering an item with an invalid id throws an error', runner(async ({ graphQLRequest }) => { const { body } = await graphQLRequest({ - query: `{ users(where: { id: "adskjnfasdfkjekfj"}) { id } }`, + query: `{ users(where: { id: { equals: "adskjnfasdfkjekfj" } }) { id } }`, }); expect(body.data).toEqual({ users: null }); const s = kind === 'autoincrement' ? 'an integer' : `a ${kind}`; diff --git a/tests/api-tests/package.json b/tests/api-tests/package.json index f8d1aa978d6..d14c3f9ac32 100644 --- a/tests/api-tests/package.json +++ b/tests/api-tests/package.json @@ -2,7 +2,7 @@ "name": "@keystone-next/api-tests-legacy", "description": "A set of tests for running against the KeystoneJS API.", "private": true, - "version": "11.0.6", + "version": "11.1.0", "author": "The KeystoneJS Development Team", "license": "MIT", "engines": { @@ -22,14 +22,14 @@ "graphql": "^15.5.1", "memoize-one": "^5.2.1", "superagent": "^6.1.0", - "supertest": "^6.1.4", + "supertest": "^6.1.5", "testcheck": "^1.0.0-rc.2", "uuid": "^8.3.2" }, "dependencies": { - "@keystone-next/testing": "^1.1.0", - "@keystone-next/types": "^23.0.0", - "@keystone-next/utils": "^1.0.3", + "@keystone-next/testing": "^1.1.1", + "@keystone-next/types": "^24.0.0", + "@keystone-next/utils": "^1.0.4", "apollo-cache-control": "^0.14.0", "express": "^4.17.1" } diff --git a/tests/api-tests/queries/cache-hints.test.ts b/tests/api-tests/queries/cache-hints.test.ts index acb37a5030d..f2146dcfcfc 100644 --- a/tests/api-tests/queries/cache-hints.test.ts +++ b/tests/api-tests/queries/cache-hints.test.ts @@ -177,7 +177,7 @@ describe('cache hints', () => { const { body, headers } = await graphQLRequest({ query: ` query { - users(where: { name: "nope" }) { + users(where: { name: { equals: "nope" } }) { name } } @@ -270,7 +270,7 @@ describe('cache hints', () => { query: ` query { posts { - author(where: { name: "nope" }) { + author(where: { name: { equals: "nope" } }) { name } } diff --git a/tests/api-tests/queries/filters.test.ts b/tests/api-tests/queries/filters.test.ts index 3b9f05c9a20..c3a731f665b 100644 --- a/tests/api-tests/queries/filters.test.ts +++ b/tests/api-tests/queries/filters.test.ts @@ -23,14 +23,16 @@ describe('filtering on field name', () => { test( 'filter works when there is no dash in field name', runner(async ({ context }) => { - const users = await context.lists.User.findMany({ where: { noDash: 'aValue' } }); + const users = await context.lists.User.findMany({ where: { noDash: { equals: 'aValue' } } }); expect(users).toEqual([]); }) ); test( 'filter works when there is one dash in field name', runner(async ({ context }) => { - const users = await context.lists.User.findMany({ where: { single_dash: 'aValue' } }); + const users = await context.lists.User.findMany({ + where: { single_dash: { equals: 'aValue' } }, + }); expect(users).toEqual([]); }) ); @@ -38,7 +40,7 @@ describe('filtering on field name', () => { 'filter works when there are multiple dashes in field name', runner(async ({ context }) => { const users = await context.lists.User.findMany({ - where: { many_many_many_dashes: 'aValue' }, + where: { many_many_many_dashes: { equals: 'aValue' } }, }); expect(users).toEqual([]); }) @@ -46,7 +48,9 @@ describe('filtering on field name', () => { test( 'filter works when there are multiple dashes in a row in a field name', runner(async ({ context }) => { - const users = await context.lists.User.findMany({ where: { multi____dash: 'aValue' } }); + const users = await context.lists.User.findMany({ + where: { multi____dash: { equals: 'aValue' } }, + }); expect(users).toEqual([]); }) ); @@ -54,7 +58,7 @@ describe('filtering on field name', () => { 'filter works when there is one dash in field name as part of a relationship', runner(async ({ context }) => { const secondaries = await context.lists.SecondaryList.findMany({ - where: { someUser_is_null: false }, + where: { NOT: { someUser: null } }, }); expect(secondaries).toEqual([]); }) diff --git a/tests/api-tests/queries/limits.test.ts b/tests/api-tests/queries/limits.test.ts index c4a9e343d46..dd0ee7e96b8 100644 --- a/tests/api-tests/queries/limits.test.ts +++ b/tests/api-tests/queries/limits.test.ts @@ -54,7 +54,7 @@ describe('maxResults Limit', () => { query: ` query { users( - where: { name_contains: "J" }, + where: { name: { contains: "J" } }, orderBy: { name: asc }, ) { name @@ -71,7 +71,7 @@ describe('maxResults Limit', () => { query: ` query { users( - where: { name: "Nope" } + where: { name: { equals: "Nope" } } ) { name } @@ -90,11 +90,11 @@ describe('maxResults Limit', () => { expect(data).toHaveProperty('usersCount'); expect(data.usersCount).toBe(users.length); - // This query is only okay because of the "first" parameter + // This query is only okay because of the "take" parameter data = await context.graphql.run({ query: ` query { - users(first: 1) { + users(take: 1) { name } } @@ -118,13 +118,13 @@ describe('maxResults Limit', () => { expectLimitsExceededError(errors, [{ path: ['users'] }]); - // The query results don't break the limits, but the "first" parameter does + // The query results don't break the limits, but the "take" parameter does ({ errors } = await context.graphql.raw({ query: ` query { users( - where: { name: "Nope" }, - first: 100000 + where: { name: { equals: "Nope" } }, + take: 100000 ) { name } @@ -165,7 +165,7 @@ describe('maxResults Limit', () => { context.totalResults = 0; // A basic query that should work let posts = await context.lists.Post.findMany({ - where: { title: 'One author' }, + where: { title: { equals: 'One author' } }, query: 'title author { name }', }); @@ -176,7 +176,7 @@ describe('maxResults Limit', () => { // Each subquery is within the limit (even though the total isn't) posts = await context.lists.Post.findMany({ where: { - OR: [{ title: 'One author' }, { title: 'Two authors' }], + OR: [{ title: { equals: 'One author' } }, { title: { equals: 'Two authors' } }], }, orderBy: { title: 'asc' }, query: 'title author(orderBy: { name: asc }) { name }', @@ -194,7 +194,7 @@ describe('maxResults Limit', () => { query: ` query { posts( - where: { title: "Three authors" }, + where: { title: { equals: "Three authors" } }, ) { title author { @@ -211,7 +211,7 @@ describe('maxResults Limit', () => { // Reset the count for each query context.totalResults = 0; posts = await context.lists.Post.findMany({ - where: { title: 'Three authors' }, + where: { title: { equals: 'Three authors' } }, query: 'title', }); @@ -241,7 +241,7 @@ describe('maxResults Limit', () => { ({ errors } = await context.graphql.raw({ query: ` query { - posts(where: { title: "Two authors" }) { + posts(where: { title: { equals: "Two authors" } }) { title author { posts { diff --git a/tests/api-tests/queries/relationships.test.ts b/tests/api-tests/queries/relationships.test.ts index c26f4370c85..a87d4960d3c 100644 --- a/tests/api-tests/queries/relationships.test.ts +++ b/tests/api-tests/queries/relationships.test.ts @@ -47,7 +47,7 @@ describe('Querying with relationship filters', () => { // Create an item that does the linking const allPosts = await context.lists.Post.findMany({ - where: { author: { name_contains: 'J' } }, + where: { author: { name: { contains: 'J' } } }, query: 'id title', }); expect(allPosts).toHaveLength(3); @@ -74,7 +74,7 @@ describe('Querying with relationship filters', () => { // Create an item that does the linking const _posts = await context.lists.Post.findMany({ - where: { author: { name_contains: 'J' } }, + where: { author: { name: { contains: 'J' } } }, query: 'id title author { id name }', }); expect(_posts).toMatchObject([{ id: posts[0].id, title: posts[0].title }]); @@ -110,7 +110,7 @@ describe('Querying with relationship filters', () => { }; test( - '_every condition', + 'every condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -118,7 +118,7 @@ describe('Querying with relationship filters', () => { // EVERY const _users = await context.lists.User.findMany({ - where: { feed_every: { title_contains: 'J' } }, + where: { feed: { every: { title: { contains: 'J' } } } }, query: 'id name feed { id title }', }); @@ -127,7 +127,7 @@ describe('Querying with relationship filters', () => { ); test( - '_some condition', + 'some condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -135,7 +135,7 @@ describe('Querying with relationship filters', () => { // SOME const _users = await context.lists.User.findMany({ - where: { feed_some: { title_contains: 'J' } }, + where: { feed: { some: { title: { contains: 'J' } } } }, query: 'id feed(orderBy: { title: asc }) { title }', }); @@ -150,7 +150,7 @@ describe('Querying with relationship filters', () => { ); test( - '_none condition', + 'none condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -158,7 +158,7 @@ describe('Querying with relationship filters', () => { // NONE const _users = await context.lists.User.findMany({ - where: { feed_none: { title_contains: 'J' } }, + where: { feed: { none: { title: { contains: 'J' } } } }, query: 'id name feed { id title }', }); @@ -191,7 +191,7 @@ describe('Querying with relationship filters', () => { }; test( - '_every condition', + 'every condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -199,7 +199,7 @@ describe('Querying with relationship filters', () => { // EVERY const _users = await context.lists.User.findMany({ - where: { feed_every: { title_contains: 'J' } }, + where: { feed: { every: { title: { contains: 'J' } } } }, query: 'id feed { id title }', }); @@ -210,7 +210,7 @@ describe('Querying with relationship filters', () => { ); test( - '_some condition', + 'some condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -218,7 +218,7 @@ describe('Querying with relationship filters', () => { // SOME const _users = await context.lists.User.findMany({ - where: { feed_some: { title_contains: 'J' } }, + where: { feed: { some: { title: { contains: 'J' } } } }, query: 'id name feed(orderBy: { title: asc }) { id title }', }); @@ -230,7 +230,7 @@ describe('Querying with relationship filters', () => { ); test( - '_none condition', + 'none condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -238,7 +238,7 @@ describe('Querying with relationship filters', () => { // NONE const _users = await context.lists.User.findMany({ - where: { feed_none: { title_contains: 'J' } }, + where: { feed: { none: { title: { contains: 'J' } } } }, query: 'id feed { title }', }); @@ -264,7 +264,7 @@ describe('Querying with relationship filters', () => { }; test( - '_every condition', + 'every condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -272,7 +272,7 @@ describe('Querying with relationship filters', () => { // EVERY const _users = await context.lists.User.findMany({ - where: { feed_every: { title_contains: 'J' } }, + where: { feed: { every: { title: { contains: 'J' } } } }, query: 'id feed { id title }', }); @@ -286,7 +286,7 @@ describe('Querying with relationship filters', () => { ); test( - '_some condition', + 'some condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -294,7 +294,7 @@ describe('Querying with relationship filters', () => { // SOME const _users = await context.lists.User.findMany({ - where: { feed_some: { author: { id: users[0].id } } }, + where: { feed: { some: { author: { id: { equals: users[0].id } } } } }, query: 'id name feed { id title }', }); expect(_users).toEqual([]); @@ -302,7 +302,7 @@ describe('Querying with relationship filters', () => { ); test( - '_none condition', + 'none condition', runner(async ({ context }) => { const create = async (listKey: string, data: any) => context.lists[listKey].createOne({ data }); @@ -310,7 +310,7 @@ describe('Querying with relationship filters', () => { // NONE const _users = await context.lists.User.findMany({ - where: { feed_none: { title_contains: 'J' } }, + where: { feed: { none: { title: { contains: 'J' } } } }, query: 'id feed { title }', }); diff --git a/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts index ca88814dfc9..62c85fb47ef 100644 --- a/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts @@ -93,7 +93,7 @@ const runner = setupTestRunner({ describe(`Many-to-many relationships`, () => { describe('Read', () => { test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -104,7 +104,7 @@ describe(`Many-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_some: { name } }, + where: { friends: { some: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) @@ -112,7 +112,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -123,7 +123,7 @@ describe(`Many-to-many relationships`, () => { ['D', 9], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_none: { name } }, + where: { friends: { none: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) @@ -131,7 +131,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -142,7 +142,7 @@ describe(`Many-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_every: { name } }, + where: { friends: { every: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) diff --git a/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts b/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts index 1d7fa945071..6be81e702de 100644 --- a/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts @@ -99,7 +99,7 @@ const runner = setupTestRunner({ describe(`Many-to-many relationships`, () => { describe('Read', () => { test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -110,7 +110,7 @@ describe(`Many-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const _users = await context.lists.User.findMany({ - where: { friends_some: { name } }, + where: { friends: { some: { name: { equals: name } } } }, }); expect(_users.length).toEqual(count); }) @@ -118,7 +118,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -129,7 +129,7 @@ describe(`Many-to-many relationships`, () => { ['D', 9], ].map(async ([name, count]) => { const _users = await context.lists.User.findMany({ - where: { friends_none: { name } }, + where: { friends: { none: { name: { equals: name } } } }, }); expect(_users.length).toEqual(count); }) @@ -137,7 +137,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -148,7 +148,7 @@ describe(`Many-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_every: { name } }, + where: { friends: { every: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) diff --git a/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts index f664a582ac9..9d77cb502f1 100644 --- a/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts @@ -104,7 +104,7 @@ describe(`One-to-many relationships`, () => { ['E', 0], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friend: { name_contains: name } }, + where: { friend: { name: { contains: name } } }, }); expect(users.length).toEqual(count); }) @@ -112,18 +112,18 @@ describe(`One-to-many relationships`, () => { }) ); test( - 'is_null: true', + 'is null', runner(async ({ context }) => { await createComplexData(context); - const users = await context.lists.User.findMany({ where: { friend_is_null: true } }); + const users = await context.lists.User.findMany({ where: { friend: null } }); expect(users.length).toEqual(5); }) ); test( - 'is_null: false', + 'is not null', runner(async ({ context }) => { await createComplexData(context); - const users = await context.lists.User.findMany({ where: { friend_is_null: false } }); + const users = await context.lists.User.findMany({ where: { NOT: { friend: null } } }); expect(users.length).toEqual(4); }) ); diff --git a/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts b/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts index e48664dd30d..09d4ec8dae5 100644 --- a/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts @@ -105,7 +105,7 @@ describe(`One-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friendOf: { name_contains: name } }, + where: { friendOf: { name: { contains: name } } }, }); expect(users.length).toEqual(count); }) @@ -113,23 +113,23 @@ describe(`One-to-many relationships`, () => { }) ); test( - 'is_null: true', + 'is null', runner(async ({ context }) => { await createReadData(context); - const users = await context.lists.User.findMany({ where: { friendOf_is_null: true } }); + const users = await context.lists.User.findMany({ where: { friendOf: null } }); expect(users.length).toEqual(5); }) ); test( - 'is_null: false', + 'is not null', runner(async ({ context }) => { await createReadData(context); - const users = await context.lists.User.findMany({ where: { friendOf_is_null: false } }); + const users = await context.lists.User.findMany({ where: { NOT: { friendOf: null } } }); expect(users.length).toEqual(6); }) ); test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -140,7 +140,7 @@ describe(`One-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_some: { name } }, + where: { friends: { some: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) @@ -148,7 +148,7 @@ describe(`One-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -159,7 +159,7 @@ describe(`One-to-many relationships`, () => { ['D', 4 + 7], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_none: { name } }, + where: { friends: { none: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) @@ -167,7 +167,7 @@ describe(`One-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -178,7 +178,7 @@ describe(`One-to-many relationships`, () => { ['D', 1 + 7], ].map(async ([name, count]) => { const users = await context.lists.User.findMany({ - where: { friends_every: { name } }, + where: { friends: { every: { name: { equals: name } } } }, }); expect(users.length).toEqual(count); }) diff --git a/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts b/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts index bb04e20fe8d..3d0dc526ca7 100644 --- a/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts @@ -79,7 +79,7 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { user, friend } = await createUserAndFriend(context); const users = await context.lists.User.findMany({ - where: { friend: { name: friend.name } }, + where: { friend: { name: { equals: friend.name } } }, }); expect(users.length).toEqual(1); expect(users[0].id).toEqual(user.id); @@ -92,45 +92,45 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { user, friend } = await createUserAndFriend(context); const users = await context.lists.User.findMany({ - where: { friendOf: { name: user.name } }, + where: { friendOf: { name: { equals: user.name } } }, }); expect(users.length).toEqual(1); expect(users[0].id).toEqual(friend.id); }) ); test( - 'Where friend: is_null: true', + 'Where friend: is null', runner(async ({ context }) => { await createInitialData(context); await createUserAndFriend(context); - const users = await context.lists.User.findMany({ where: { friend_is_null: true } }); + const users = await context.lists.User.findMany({ where: { friend: null } }); expect(users.length).toEqual(4); }) ); test( - 'Where friendOf: is_null: true', + 'Where friendOf: is null', runner(async ({ context }) => { await createInitialData(context); await createUserAndFriend(context); - const users = await context.lists.User.findMany({ where: { friendOf_is_null: true } }); + const users = await context.lists.User.findMany({ where: { friendOf: null } }); expect(users.length).toEqual(4); }) ); test( - 'Where friend: is_null: false', + 'Where friend: is not null', runner(async ({ context }) => { await createInitialData(context); await createUserAndFriend(context); - const users = await context.lists.User.findMany({ where: { friend_is_null: false } }); + const users = await context.lists.User.findMany({ where: { NOT: { friend: null } } }); expect(users.length).toEqual(1); }) ); test( - 'Where friendOf: is_null: false', + 'Where friendOf: is not null', runner(async ({ context }) => { await createInitialData(context); await createUserAndFriend(context); - const users = await context.lists.User.findMany({ where: { friendOf_is_null: false } }); + const users = await context.lists.User.findMany({ where: { NOT: { friendOf: null } } }); expect(users.length).toEqual(1); }) ); @@ -150,7 +150,7 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { friend } = await createUserAndFriend(context); const count = await context.lists.User.count({ - where: { friend: { name: friend.name } }, + where: { friend: { name: { equals: friend.name } } }, }); expect(count).toEqual(1); }) @@ -162,7 +162,7 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { user } = await createUserAndFriend(context); const count = await context.lists.User.count({ - where: { friendOf: { name: user.name } }, + where: { friendOf: { name: { equals: user.name } } }, }); expect(count).toEqual(1); }) @@ -172,7 +172,7 @@ describe(`One-to-one relationships`, () => { runner(async ({ context }) => { await createInitialData(context); await createUserAndFriend(context); - const count = await context.lists.User.count({ where: { friend_is_null: true } }); + const count = await context.lists.User.count({ where: { friend: null } }); expect(count).toEqual(4); }) ); @@ -182,7 +182,7 @@ describe(`One-to-one relationships`, () => { runner(async ({ context }) => { await createInitialData(context); await createUserAndFriend(context); - const count = await context.lists.User.count({ where: { friendOf_is_null: true } }); + const count = await context.lists.User.count({ where: { friendOf: null } }); expect(count).toEqual(4); }) ); diff --git a/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts index 446779b4dc4..fb9ca10d78f 100644 --- a/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts @@ -100,7 +100,7 @@ const runner = setupTestRunner({ describe(`Many-to-many relationships`, () => { describe('Read', () => { test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -111,7 +111,7 @@ describe(`Many-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_some: { name } }, + where: { locations: { some: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -119,7 +119,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -130,7 +130,7 @@ describe(`Many-to-many relationships`, () => { ['D', 9], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_none: { name } }, + where: { locations: { none: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -138,7 +138,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -149,7 +149,7 @@ describe(`Many-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_every: { name } }, + where: { locations: { every: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -171,7 +171,7 @@ describe(`Many-to-many relationships`, () => { ); test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -182,7 +182,7 @@ describe(`Many-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const _count = await context.lists.Company.count({ - where: { locations_some: { name } }, + where: { locations: { some: { name: { equals: name } } } }, }); expect(_count).toEqual(count); }) @@ -190,7 +190,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -201,7 +201,7 @@ describe(`Many-to-many relationships`, () => { ['D', 9], ].map(async ([name, count]) => { const _count = await context.lists.Company.count({ - where: { locations_none: { name } }, + where: { locations: { none: { name: { equals: name } } } }, }); expect(_count).toEqual(count); }) @@ -209,7 +209,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -220,7 +220,7 @@ describe(`Many-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const _count = await context.lists.Company.count({ - where: { locations_every: { name } }, + where: { locations: { every: { name: { equals: name } } } }, }); expect(_count).toEqual(count); }) diff --git a/tests/api-tests/relationships/crud/many-to-many.test.ts b/tests/api-tests/relationships/crud/many-to-many.test.ts index d7e00b5d4e9..5f9309524e3 100644 --- a/tests/api-tests/relationships/crud/many-to-many.test.ts +++ b/tests/api-tests/relationships/crud/many-to-many.test.ts @@ -114,7 +114,7 @@ const runner = setupTestRunner({ describe(`Many-to-many relationships`, () => { describe('Read', () => { test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -125,7 +125,7 @@ describe(`Many-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_some: { name } }, + where: { locations: { some: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -133,7 +133,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -144,7 +144,7 @@ describe(`Many-to-many relationships`, () => { ['D', 9], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_none: { name } }, + where: { locations: { none: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -152,7 +152,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -163,7 +163,7 @@ describe(`Many-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_every: { name } }, + where: { locations: { every: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -184,7 +184,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -195,7 +195,7 @@ describe(`Many-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const _count = await context.lists.Company.count({ - where: { locations_some: { name } }, + where: { locations: { some: { name: { equals: name } } } }, }); expect(_count).toEqual(count); }) @@ -203,7 +203,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -214,7 +214,7 @@ describe(`Many-to-many relationships`, () => { ['D', 9], ].map(async ([name, count]) => { const _count = await context.lists.Company.count({ - where: { locations_none: { name } }, + where: { locations: { none: { name: { equals: name } } } }, }); expect(_count).toEqual(count); }) @@ -222,7 +222,7 @@ describe(`Many-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -233,7 +233,7 @@ describe(`Many-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const _count = await context.lists.Company.count({ - where: { locations_every: { name } }, + where: { locations: { every: { name: { equals: name } } } }, }); expect(_count).toEqual(count); }) diff --git a/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts index 5421134c607..d7b96de0065 100644 --- a/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts @@ -131,7 +131,7 @@ describe(`One-to-many relationships`, () => { ['E', 0], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { location: { name_contains: name } }, + where: { location: { name: { contains: name } } }, }); expect(companies.length).toEqual(count); }) @@ -139,21 +139,21 @@ describe(`One-to-many relationships`, () => { }) ); test( - 'is_null: true', + 'is null', runner(async ({ context }) => { await createComplexData(context); const companies = await context.lists.Company.findMany({ - where: { location_is_null: true }, + where: { location: null }, }); expect(companies.length).toEqual(1); }) ); test( - 'is_null: false', + 'is not null', runner(async ({ context }) => { await createComplexData(context); const companies = await context.lists.Company.findMany({ - where: { location_is_null: false }, + where: { NOT: { location: null } }, }); expect(companies.length).toEqual(4); }) diff --git a/tests/api-tests/relationships/crud/one-to-many.test.ts b/tests/api-tests/relationships/crud/one-to-many.test.ts index bc780b80485..6585dbe2f75 100644 --- a/tests/api-tests/relationships/crud/one-to-many.test.ts +++ b/tests/api-tests/relationships/crud/one-to-many.test.ts @@ -118,7 +118,7 @@ describe(`One-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const locations = await context.lists.Location.findMany({ - where: { company: { name_contains: name } }, + where: { company: { name: { contains: name } } }, }); expect(locations.length).toEqual(count); }) @@ -126,27 +126,27 @@ describe(`One-to-many relationships`, () => { }) ); test( - 'is_null: true', + 'is null', runner(async ({ context }) => { await createReadData(context); const locations = await context.lists.Location.findMany({ - where: { company_is_null: true }, + where: { company: null }, }); expect(locations.length).toEqual(1); }) ); test( - 'is_null: false', + 'is not null', runner(async ({ context }) => { await createReadData(context); const locations = await context.lists.Location.findMany({ - where: { company_is_null: false }, + where: { NOT: { company: null } }, }); expect(locations.length).toEqual(6); }) ); test( - '_some', + 'some', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -157,7 +157,7 @@ describe(`One-to-many relationships`, () => { ['D', 0], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_some: { name } }, + where: { locations: { some: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -165,7 +165,7 @@ describe(`One-to-many relationships`, () => { }) ); test( - '_none', + 'none', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -176,7 +176,7 @@ describe(`One-to-many relationships`, () => { ['D', 4], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_none: { name } }, + where: { locations: { none: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) @@ -184,7 +184,7 @@ describe(`One-to-many relationships`, () => { }) ); test( - '_every', + 'every', runner(async ({ context }) => { await createReadData(context); await Promise.all( @@ -195,7 +195,7 @@ describe(`One-to-many relationships`, () => { ['D', 1], ].map(async ([name, count]) => { const companies = await context.lists.Company.findMany({ - where: { locations_every: { name } }, + where: { locations: { every: { name: { equals: name } } } }, }); expect(companies.length).toEqual(count); }) diff --git a/tests/api-tests/relationships/crud/one-to-one.test.ts b/tests/api-tests/relationships/crud/one-to-one.test.ts index e914749cbf4..b4117a0c4b1 100644 --- a/tests/api-tests/relationships/crud/one-to-one.test.ts +++ b/tests/api-tests/relationships/crud/one-to-one.test.ts @@ -118,10 +118,10 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { location, company } = await createCompanyAndLocation(context); const locations = await context.lists.Location.findMany({ - where: { company: { name: company.name } }, + where: { company: { name: { equals: company.name } } }, }); const companies = await context.lists.Company.findMany({ - where: { location: { name: location.name } }, + where: { location: { name: { equals: location.name } } }, }); expect(locations.length).toEqual(1); expect(locations[0].id).toEqual(location.id); @@ -135,10 +135,10 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { location, company } = await createLocationAndCompany(context); const locations = await context.lists.Location.findMany({ - where: { company: { name: company.name } }, + where: { company: { name: { equals: company.name } } }, }); const companies = await context.lists.Company.findMany({ - where: { location: { name: location.name } }, + where: { location: { name: { equals: location.name } } }, }); expect(locations.length).toEqual(1); expect(locations[0].id).toEqual(location.id); @@ -147,60 +147,60 @@ describe(`One-to-one relationships`, () => { }) ); test( - 'Where A: is_null: true', + 'Where A: is null', runner(async ({ context }) => { await createInitialData(context); await createCompanyAndLocation(context); const locations = await context.lists.Location.findMany({ - where: { company_is_null: true }, + where: { company: null }, }); const companies = await context.lists.Company.findMany({ - where: { location_is_null: true }, + where: { location: null }, }); expect(locations.length).toEqual(4); expect(companies.length).toEqual(3); }) ); test( - 'Where B: is_null: true', + 'Where B: is null', runner(async ({ context }) => { await createInitialData(context); await createLocationAndCompany(context); const locations = await context.lists.Location.findMany({ - where: { company_is_null: true }, + where: { company: null }, }); const companies = await context.lists.Company.findMany({ - where: { location_is_null: true }, + where: { location: null }, }); expect(locations.length).toEqual(4); expect(companies.length).toEqual(3); }) ); test( - 'Where A: is_null: false', + 'Where A: is not null', runner(async ({ context }) => { await createInitialData(context); await createCompanyAndLocation(context); const locations = await context.lists.Location.findMany({ - where: { company_is_null: false }, + where: { NOT: { company: null } }, }); const companies = await context.lists.Company.findMany({ - where: { location_is_null: false }, + where: { NOT: { location: null } }, }); expect(locations.length).toEqual(1); expect(companies.length).toEqual(1); }) ); test( - 'Where B: is_null: false', + 'Where B: is not null', runner(async ({ context }) => { await createInitialData(context); await createLocationAndCompany(context); const locations = await context.lists.Location.findMany({ - where: { company_is_null: false }, + where: { NOT: { company: null } }, }); const companies = await context.lists.Company.findMany({ - where: { location_is_null: false }, + where: { NOT: { location: null } }, }); expect(locations.length).toEqual(1); expect(companies.length).toEqual(1); @@ -224,10 +224,10 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { location, company } = await createCompanyAndLocation(context); const locationsCount = await context.lists.Location.count({ - where: { company: { name: company.name } }, + where: { company: { name: { equals: company.name } } }, }); const companiesCount = await context.lists.Company.count({ - where: { location: { name: location.name } }, + where: { location: { name: { equals: location.name } } }, }); expect(companiesCount).toEqual(1); expect(locationsCount).toEqual(1); @@ -239,10 +239,10 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); const { location, company } = await createLocationAndCompany(context); const locationsCount = await context.lists.Location.count({ - where: { company: { name: company.name } }, + where: { company: { name: { equals: company.name } } }, }); const companiesCount = await context.lists.Company.count({ - where: { location: { name: location.name } }, + where: { location: { name: { equals: location.name } } }, }); expect(companiesCount).toEqual(1); expect(locationsCount).toEqual(1); @@ -254,10 +254,10 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); await createCompanyAndLocation(context); const locationsCount = await context.lists.Location.count({ - where: { company_is_null: true }, + where: { company: null }, }); const companiesCount = await context.lists.Company.count({ - where: { location_is_null: true }, + where: { location: null }, }); expect(companiesCount).toEqual(3); expect(locationsCount).toEqual(4); @@ -269,10 +269,10 @@ describe(`One-to-one relationships`, () => { await createInitialData(context); await createLocationAndCompany(context); const locationsCount = await context.lists.Location.count({ - where: { company_is_null: true }, + where: { company: null }, }); const companiesCount = await context.lists.Company.count({ - where: { location_is_null: true }, + where: { location: null }, }); expect(companiesCount).toEqual(3); expect(locationsCount).toEqual(4); diff --git a/tests/api-tests/relationships/filtering/access-control.test.ts b/tests/api-tests/relationships/filtering/access-control.test.ts index e49208685d5..df0b3715ba7 100644 --- a/tests/api-tests/relationships/filtering/access-control.test.ts +++ b/tests/api-tests/relationships/filtering/access-control.test.ts @@ -24,7 +24,7 @@ const runner = setupTestRunner({ }, access: { // Limit read access to the first post only - read: { name_in: [postNames[1]] }, + read: { name: { in: [postNames[1]] } }, }, }), }), @@ -97,7 +97,7 @@ describe('relationship filtering with access control', () => { where: { id: user.id }, // Knowingly filter to an ID I don't have read access to // to see if the filter is correctly "AND"d with the access control - query: `id username posts(where: { id_in: ["${postIds[2]}"] }) { id }`, + query: `id username posts(where: { id: { in: ["${postIds[2]}"] } }) { id }`, }); expect(item).toMatchObject({ id: expect.any(String), username, posts: [] }); diff --git a/tests/api-tests/relationships/filtering/filtering.test.ts b/tests/api-tests/relationships/filtering/filtering.test.ts index 3caff8d17b8..32224aea55a 100644 --- a/tests/api-tests/relationships/filtering/filtering.test.ts +++ b/tests/api-tests/relationships/filtering/filtering.test.ts @@ -36,7 +36,10 @@ describe('relationship filtering', () => { const users = await context.lists.User.findMany({ where: { - AND: [{ company: { name_contains: 'in' } }, { company: { name_contains: 'll' } }], + AND: [ + { company: { name: { contains: 'in' } } }, + { company: { name: { contains: 'll' } } }, + ], }, query: 'id company { id name }', }); @@ -63,7 +66,10 @@ describe('relationship filtering', () => { const users = await context.lists.User.findMany({ where: { - OR: [{ company: { name_contains: 'in' } }, { company: { name_contains: 'xx' } }], + OR: [ + { company: { name: { contains: 'in' } } }, + { company: { name: { contains: 'xx' } } }, + ], }, query: 'id company { id name }', }); @@ -93,8 +99,8 @@ describe('relationship filtering', () => { const users = (await context.lists.User.findMany({ where: { AND: [ - { posts_some: { content_contains: 'hi' } }, - { posts_some: { content_contains: 'lo' } }, + { posts: { some: { content: { contains: 'hi' } } } }, + { posts: { some: { content: { contains: 'lo' } } } }, ], }, query: 'id posts { id content }', @@ -125,8 +131,8 @@ describe('relationship filtering', () => { const users = (await context.lists.User.findMany({ where: { OR: [ - { posts_some: { content_contains: 'o w' } }, - { posts_some: { content_contains: '? O' } }, + { posts: { some: { content: { contains: 'o w' } } } }, + { posts: { some: { content: { contains: '? O' } } } }, ], }, query: 'id posts { id content }', @@ -199,7 +205,10 @@ describe('relationship filtering', () => { posts: { content: string }[]; }[]; const users = (await context.lists.User.findMany({ - where: { company: { name: adsCompany.name }, posts_every: { content: 'spam' } }, + where: { + company: { name: { equals: adsCompany.name } }, + posts: { every: { content: { equals: 'spam' } } }, + }, query: 'id company { id name } posts { content }', })) as T; expect(users).toHaveLength(2); @@ -209,7 +218,10 @@ describe('relationship filtering', () => { // adsCompany users with no spam const users2 = (await context.lists.User.findMany({ - where: { company: { name: adsCompany.name }, posts_none: { content: 'spam' } }, + where: { + company: { name: { equals: adsCompany.name } }, + posts: { none: { content: { equals: 'spam' } } }, + }, query: 'id company { id name } posts { content }', })) as T; @@ -220,7 +232,10 @@ describe('relationship filtering', () => { // adsCompany users with some spam const users3 = (await context.lists.User.findMany({ - where: { company: { name: adsCompany.name }, posts_some: { content: 'spam' } }, + where: { + company: { name: { equals: adsCompany.name } }, + posts: { some: { content: { equals: 'spam' } } }, + }, query: 'id company { id name } posts { content }', })) as T; diff --git a/tests/api-tests/relationships/filtering/nested.test.ts b/tests/api-tests/relationships/filtering/nested.test.ts index 9679c5122b8..daf5829477b 100644 --- a/tests/api-tests/relationships/filtering/nested.test.ts +++ b/tests/api-tests/relationships/filtering/nested.test.ts @@ -36,7 +36,7 @@ describe('relationship filtering', () => { }); const users = (await context.lists.User.findMany({ - query: `id posts (where: { content_contains: "hi" }){ id content }`, + query: `id posts (where: { content: { contains: "hi" } }){ id content }`, })) as { id: IdType; posts: { id: IdType; content: string }[] }[]; expect(users).toHaveLength(2); users[0].posts = users[0].posts.map(({ id }) => id).sort(); @@ -63,7 +63,7 @@ describe('relationship filtering', () => { }); const users = await context.lists.User.findMany({ - query: 'id posts(first: 1, orderBy: { content: asc }) { id }', + query: 'id posts(take: 1, orderBy: { content: asc }) { id }', }); expect(users).toContainEqual({ id: user.id, posts: [ids[0]] }); expect(users).toContainEqual({ id: user2.id, posts: [ids[0]] }); @@ -86,7 +86,7 @@ describe('relationship filtering', () => { const users = await context.lists.User.findMany({ query: - 'id posts(where: { AND: [{ content_contains: "hi" }, { content_contains: "lo" }] }){ id }', + 'id posts(where: { AND: [{ content: { contains: "hi" } }, { content: { contains: "lo" } }] }){ id }', }); expect(users).toContainEqual({ id: user.id, posts: [ids[2]] }); @@ -110,7 +110,7 @@ describe('relationship filtering', () => { const users = await context.lists.User.findMany({ query: - 'id posts(where: { OR: [{ content_contains: "i w" }, { content_contains: "? O" }] }){ id content }', + 'id posts(where: { OR: [{ content: { contains: "i w" } }, { content: { contains: "? O" } }] }){ id content }', }); expect(users).toContainEqual({ id: user.id, @@ -129,7 +129,7 @@ describe('relationship filtering', () => { await context.lists.User.createOne({ data: {} }); const users = await context.lists.User.findMany({ - where: { posts_some: { content_contains: 'foo' } }, + where: { posts: { some: { content: { contains: 'foo' } } } }, query: 'posts { id }', }); expect(users).toHaveLength(0); @@ -174,7 +174,7 @@ describe('relationship meta filtering', () => { }); const users = await context.lists.User.findMany({ - query: 'id postsCount(where: { content_contains: "hi" })', + query: 'id postsCount(where: { content: { contains: "hi" } })', }); expect(users).toHaveLength(2); expect(users).toContainEqual({ id: user.id, postsCount: 2 }); @@ -197,7 +197,7 @@ describe('relationship meta filtering', () => { }); const users = await context.lists.User.findMany({ - query: `id postsCount(where: { AND: [{ content_contains: "hi" }, { content_contains: "lo" }] })`, + query: `id postsCount(where: { AND: [{ content: { contains: "hi" } }, { content: { contains: "lo" } }] })`, }); expect(users).toHaveLength(2); @@ -222,7 +222,7 @@ describe('relationship meta filtering', () => { const users = await context.lists.User.findMany({ query: - 'id postsCount(where: { OR: [{ content_contains: "i w" }, { content_contains: "? O" }] })', + 'id postsCount(where: { OR: [{ content: { contains: "i w" } }, { content: { contains: "? O" } }] })', }); expect(users).toHaveLength(2); expect(users).toContainEqual({ id: user.id, postsCount: 2 }); diff --git a/tests/api-tests/relationships/many-to-one-to-one.test.ts b/tests/api-tests/relationships/many-to-one-to-one.test.ts index 0bbf84d21ab..b56821167b4 100644 --- a/tests/api-tests/relationships/many-to-one-to-one.test.ts +++ b/tests/api-tests/relationships/many-to-one-to-one.test.ts @@ -123,7 +123,11 @@ describe(`One-to-one relationships`, () => { const owner = await createCompanyAndLocation(context); const name1 = owner.companies[0].location.custodians[0].name; const owners = await context.lists.Owner.findMany({ - where: { companies_some: { location: { custodians_some: { name: name1 } } } }, + where: { + companies: { + some: { location: { custodians: { some: { name: { equals: name1 } } } } }, + }, + }, query: 'id companies { location { custodians { name } } }', }); expect(owners.length).toEqual(1); @@ -137,7 +141,9 @@ describe(`One-to-one relationships`, () => { const owner = await createCompanyAndLocation(context); const name1 = owner.name; const custodians = await context.lists.Custodian.findMany({ - where: { locations_some: { company: { owners_some: { name: name1 } } } }, + where: { + locations: { some: { company: { owners: { some: { name: { equals: name1 } } } } } }, + }, query: 'id locations { company { owners { name } } }', }); expect(custodians.length).toEqual(2); @@ -151,10 +157,16 @@ describe(`One-to-one relationships`, () => { const name1 = owner.name; const owners = await context.lists.Owner.findMany({ where: { - companies_some: { - location: { - custodians_some: { - locations_some: { company: { owners_some: { name: name1 } } }, + companies: { + some: { + location: { + custodians: { + some: { + locations: { + some: { company: { owners: { some: { name: { equals: name1 } } } } }, + }, + }, + }, }, }, }, @@ -174,10 +186,16 @@ describe(`One-to-one relationships`, () => { const custodians = await context.lists.Custodian.findMany({ where: { - locations_some: { - company: { - owners_some: { - companies_some: { location: { custodians_some: { name: name1 } } }, + locations: { + some: { + company: { + owners: { + some: { + companies: { + some: { location: { custodians: { some: { name: { equals: name1 } } } } }, + }, + }, + }, }, }, }, diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts index a1929770098..f0e5bcdfb62 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts @@ -84,7 +84,7 @@ describe('no access control', () => { // Sanity check that the items are actually created const allNotes = await context.lists.Note.findMany({ - where: { id_in: user.notes.map(({ id }) => id) }, + where: { id: { in: user.notes.map(({ id }) => id) } }, query: 'id content', }); @@ -125,7 +125,7 @@ describe('no access control', () => { // Sanity check that the items are actually created const allNotes = await context.lists.Note.findMany({ - where: { id_in: user.notes.map(({ id }) => id) }, + where: { id: { in: user.notes.map(({ id }) => id) } }, query: 'id content', }); diff --git a/tests/api-tests/relationships/nested-mutations/create-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-many.test.ts index 92b0dcb2226..0440365f3aa 100644 --- a/tests/api-tests/relationships/nested-mutations/create-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-many.test.ts @@ -131,7 +131,7 @@ describe('no access control', () => { // Sanity check that the items are actually created const notes = await context.lists.Note.findMany({ - where: { id_in: user1.notes.map(({ id }) => id) }, + where: { id: { in: user1.notes.map(({ id }) => id) } }, }); expect(notes).toHaveLength(user1.notes.length); @@ -187,7 +187,7 @@ describe('no access control', () => { // Sanity check that the items are actually created const notes = await context.lists.Note.findMany({ - where: { id_in: _user.notes.map(({ id }) => id) }, + where: { id: { in: _user.notes.map(({ id }) => id) } }, }); expect(notes).toHaveLength(_user.notes.length); }) @@ -218,7 +218,9 @@ describe('with access control', () => { }); expect(data).toEqual({ createUserToNotesNoRead: { id: expect.any(String), notes: null } }); - expectAccessDenied(errors, [{ path: ['createUserToNotesNoRead', 'notes'] }]); + expectAccessDenied('dev', false, undefined, errors, [ + { path: ['createUserToNotesNoRead', 'notes'] }, + ]); }) ); @@ -307,10 +309,10 @@ describe('with access control', () => { // Confirm it didn't insert either of the records anyway const allNoteNoCreates = await context.lists.NoteNoCreate.findMany({ - where: { content: noteContent }, + where: { content: { equals: noteContent } }, }); const allUserToNotesNoCreates = await context.lists.UserToNotesNoCreate.findMany({ - where: { username: userName }, + where: { username: { equals: userName } }, }); expect(allNoteNoCreates).toMatchObject([]); expect(allUserToNotesNoCreates).toMatchObject([]); @@ -355,7 +357,7 @@ describe('with access control', () => { // Confirm it didn't insert the record anyway const items = await context.lists.NoteNoCreate.findMany({ - where: { content: noteContent }, + where: { content: { equals: noteContent } }, }); expect(items).toMatchObject([]); }) diff --git a/tests/api-tests/relationships/nested-mutations/create-singular.test.ts b/tests/api-tests/relationships/nested-mutations/create-singular.test.ts index 5126d0e0c9a..feedce7adc8 100644 --- a/tests/api-tests/relationships/nested-mutations/create-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-singular.test.ts @@ -265,14 +265,14 @@ describe('with access control', () => { } // Confirm it didn't insert either of the records anyway const data1 = await context.lists[group.name].findMany({ - where: { name: groupName }, + where: { name: { equals: groupName } }, query: 'id name', }); expect(data1).toMatchObject([]); // Confirm it didn't insert either of the records anyway const data2 = await context.lists[`EventTo${group.name}`].findMany({ - where: { title: eventName }, + where: { title: { equals: eventName } }, query: 'id title', }); expect(data2).toMatchObject([]); @@ -326,7 +326,7 @@ describe('with access control', () => { // Confirm it didn't insert the record anyway const groups = await context.lists[group.name].findMany({ - where: { name: groupName }, + where: { name: { equals: groupName } }, query: 'id name', }); expect(groups).toMatchObject([]); diff --git a/tests/api-tests/relationships/shared-names.test.ts b/tests/api-tests/relationships/shared-names.test.ts index 11e4724c4f0..2d058c296c8 100644 --- a/tests/api-tests/relationships/shared-names.test.ts +++ b/tests/api-tests/relationships/shared-names.test.ts @@ -129,7 +129,7 @@ test( runner(async ({ context }) => { await createInitialData(context); const employees = await context.lists.Employee.findMany({ - where: { company: { employees_some: { role: { name: 'RoleA' } } } }, + where: { company: { employees: { some: { role: { name: { equals: 'RoleA' } } } } } }, query: 'id name', }); expect(employees).toHaveLength(1); diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 9b824b50bf2..5b85916b4cc 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -17,21 +17,24 @@ export const apiTestConfig = ( }); const unpackErrors = (errors: readonly any[] | undefined) => - (errors || []).map(({ locations, extensions: { exception, ...extensions }, ...unpacked }) => ({ - extensions, - ...unpacked, - })); + (errors || []).map(({ locations, ...unpacked }) => unpacked); const j = (messages: string[]) => messages.map(m => ` - ${m}`).join('\n'); +// FIXME: It's not clear to me right now why sometimes +// we get an expcetion, and other times we don't - TL export const expectInternalServerError = ( errors: readonly any[] | undefined, + expectException: boolean, args: { path: any[]; message: string }[] ) => { const unpackedErrors = unpackErrors(errors); expect(unpackedErrors).toEqual( args.map(({ path, message }) => ({ - extensions: { code: 'INTERNAL_SERVER_ERROR' }, + extensions: { + code: 'INTERNAL_SERVER_ERROR', + ...(expectException ? { exception: { locations: [expect.any(Object)], message } } : {}), + }, path, message, })) @@ -52,17 +55,36 @@ export const expectGraphQLValidationError = ( }; export const expectAccessDenied = ( + mode: 'dev' | 'production', + httpQuery: boolean, + _debug: boolean | undefined, errors: readonly any[] | undefined, args: { path: (string | number)[] }[] ) => { const unpackedErrors = (errors || []).map(({ locations, ...unpacked }) => ({ ...unpacked, })); + const message = 'You do not have access to this resource'; + // We expect to see debug details if: + // - httpQuery is false + // - graphql.debug is true or + // - graphql.debug is undefined and mode !== production or + const expectDebug = + _debug === true || (_debug === undefined && mode !== 'production') || !httpQuery; + // We expect to see the Apollo exception under the same conditions, but only if + // httpQuery is also true. + const expectException = httpQuery && expectDebug; + expect(unpackedErrors).toEqual( args.map(({ path }) => ({ - extensions: { code: undefined }, + extensions: { + code: httpQuery ? 'INTERNAL_SERVER_ERROR' : undefined, + ...(expectException + ? { exception: { stacktrace: expect.arrayContaining([`Error: ${message}`]) } } + : {}), + }, path, - message: 'You do not have access to this resource', + message, })) ); }; @@ -84,28 +106,56 @@ export const expectValidationError = ( }; export const expectExtensionError = ( + mode: 'dev' | 'production', + httpQuery: boolean, + _debug: boolean | undefined, errors: readonly any[] | undefined, extensionName: string, - args: { path: (string | number)[]; messages: string[] }[] + args: { path: (string | number)[]; messages: string[]; debug: any[] }[] ) => { const unpackedErrors = unpackErrors(errors); expect(unpackedErrors).toEqual( - args.map(({ path, messages }) => ({ - extensions: { code: undefined }, - path, - message: `An error occured while running "${extensionName}".\n${j(messages)}`, - })) + args.map(({ path, messages, debug }) => { + const message = `An error occured while running "${extensionName}".\n${j(messages)}`; + const stacktrace = message.split('\n'); + stacktrace[0] = `Error: ${stacktrace[0]}`; + + // We expect to see debug details if: + // - httpQuery is false + // - graphql.debug is true or + // - graphql.debug is undefined and mode !== production or + const expectDebug = + _debug === true || (_debug === undefined && mode !== 'production') || !httpQuery; + // We expect to see the Apollo exception under the same conditions, but only if + // httpQuery is also true. + const expectException = httpQuery && expectDebug; + + return { + extensions: { + code: 'INTERNAL_SERVER_ERROR', + ...(expectException + ? { exception: { debug, stacktrace: expect.arrayContaining(stacktrace) } } + : {}), + ...(expectDebug ? { debug } : {}), + }, + path, + message, + }; + }) ); }; export const expectPrismaError = ( errors: readonly any[] | undefined, - args: { path: any[]; message: string }[] + args: { path: any[]; message: string; code: string; target: string[] }[] ) => { const unpackedErrors = unpackErrors(errors); expect(unpackedErrors).toEqual( - args.map(({ path, message }) => ({ - extensions: { code: 'INTERNAL_SERVER_ERROR' }, + args.map(({ path, message, code, target }) => ({ + extensions: { + code: 'INTERNAL_SERVER_ERROR', + exception: { clientVersion: '2.29.1', code, meta: { target } }, + }, path, message, })) diff --git a/tests/benchmarks/CHANGELOG.md b/tests/benchmarks/CHANGELOG.md index 562a52338c1..5af1efc132f 100644 --- a/tests/benchmarks/CHANGELOG.md +++ b/tests/benchmarks/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystonejs/benchmarks +## 7.0.7 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + - @keystone-next/testing@1.1.1 + ## 7.0.6 ### Patch Changes diff --git a/tests/benchmarks/package.json b/tests/benchmarks/package.json index 2899ace5a3a..0d27253703b 100644 --- a/tests/benchmarks/package.json +++ b/tests/benchmarks/package.json @@ -2,7 +2,7 @@ "name": "@keystone-next/benchmarks-legacy", "description": "A set of benchmarks for running against the KeystoneJS API.", "private": true, - "version": "7.0.6", + "version": "7.0.7", "author": "The KeystoneJS Development Team", "license": "MIT", "engines": { @@ -14,9 +14,9 @@ "repository": "https://github.com/keystonejs/keystone/tree/master/tests/benchmarks", "homepage": "https://github.com/keystonejs/keystone", "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0", - "@keystone-next/testing": "^1.1.0", + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0", + "@keystone-next/testing": "^1.1.1", "cookie-signature": "^1.1.0", "testcheck": "^1.0.0-rc.2" } diff --git a/tests/examples-smoke-tests/custom-admin-ui-pages.test.ts b/tests/examples-smoke-tests/custom-admin-ui-pages.test.ts index 408baf40399..8b3dd98613a 100644 --- a/tests/examples-smoke-tests/custom-admin-ui-pages.test.ts +++ b/tests/examples-smoke-tests/custom-admin-ui-pages.test.ts @@ -11,8 +11,7 @@ exampleProjectTests('custom-admin-ui-pages', browserType => { }); test('Load list', async () => { await page.goto('http://localhost:3000/custom-page'); - const content = await page.textContent('body h1'); - expect(content).toBe('Hello this is a custom page'); + await page.waitForSelector('main h1:has-text("This is a custom Admin UI page")'); }); afterAll(async () => { await browser.close(); diff --git a/tests/examples-smoke-tests/package.json b/tests/examples-smoke-tests/package.json index e043d17e77d..55098b68602 100644 --- a/tests/examples-smoke-tests/package.json +++ b/tests/examples-smoke-tests/package.json @@ -14,7 +14,7 @@ "@types/tough-cookie": "^4.0.1", "execa": "^5.1.1", "node-fetch": "^2.6.1", - "playwright": "^1.13.1", + "playwright": "^1.14.0", "tree-kill": "^1.2.2" } } diff --git a/tests/test-projects/basic/CHANGELOG.md b/tests/test-projects/basic/CHANGELOG.md index bb5b655a22f..49f6ad1855c 100644 --- a/tests/test-projects/basic/CHANGELOG.md +++ b/tests/test-projects/basic/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/test-projects-basic +## 0.0.3 + +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 + ## 0.0.2 ### Patch Changes diff --git a/tests/test-projects/basic/package.json b/tests/test-projects/basic/package.json index ef134c60847..034d10a328c 100644 --- a/tests/test-projects/basic/package.json +++ b/tests/test-projects/basic/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/test-projects-basic", - "version": "0.0.2", + "version": "0.0.3", "private": true, "license": "MIT", "scripts": { @@ -9,8 +9,8 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^13.0.0", - "@keystone-next/keystone": "^23.0.0" + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" }, "devDependencies": { "typescript": "^4.3.5" diff --git a/tests/test-projects/basic/schema.graphql b/tests/test-projects/basic/schema.graphql index 49a0f225167..e194b7cb406 100644 --- a/tests/test-projects/basic/schema.graphql +++ b/tests/test-projects/basic/schema.graphql @@ -16,36 +16,75 @@ enum TaskPriorityType { input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - label: String - label_not: String - label_contains: String - label_not_contains: String - label_in: [String] - label_not_in: [String] - priority: TaskPriorityType - priority_not: TaskPriorityType - priority_in: [TaskPriorityType] - priority_not_in: [TaskPriorityType] - isComplete: Boolean - isComplete_not: Boolean + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter assignedTo: PersonWhereInput - assignedTo_is_null: Boolean - finishBy: String - finishBy_not: String - finishBy_lt: String - finishBy_lte: String - finishBy_gt: String - finishBy_gte: String - finishBy_in: [String] - finishBy_not_in: [String] + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter } input TaskWhereUniqueInput { @@ -103,7 +142,7 @@ type Person { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] tasksCount(where: TaskWhereInput! = {}): Int @@ -112,23 +151,16 @@ type Person { input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] - id: ID - id_not: ID - id_lt: ID - id_lte: ID - id_gt: ID - id_gte: ID - id_in: [ID!] - id_not_in: [ID!] - name: String - name_not: String - name_contains: String - name_not_contains: String - name_in: [String] - name_not_in: [String] - tasks_every: TaskWhereInput - tasks_some: TaskWhereInput - tasks_none: TaskWhereInput + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput } input PersonWhereUniqueInput { @@ -194,7 +226,7 @@ type Query { tasks( where: TaskWhereInput! = {} orderBy: [TaskOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Task!] task(where: TaskWhereUniqueInput!): Task @@ -202,7 +234,7 @@ type Query { people( where: PersonWhereInput! = {} orderBy: [PersonOrderByInput!]! = [] - first: Int + take: Int skip: Int! = 0 ): [Person!] person(where: PersonWhereUniqueInput!): Person diff --git a/tests/test-projects/crud-notifications/CHANGELOG.md b/tests/test-projects/crud-notifications/CHANGELOG.md new file mode 100644 index 00000000000..4315359a821 --- /dev/null +++ b/tests/test-projects/crud-notifications/CHANGELOG.md @@ -0,0 +1,8 @@ +# @keystone-next/test-projects-crud-notifications + +## 0.0.3 +### Patch Changes + +- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: + - @keystone-next/fields@14.0.0 + - @keystone-next/keystone@24.0.0 diff --git a/tests/test-projects/crud-notifications/README.md b/tests/test-projects/crud-notifications/README.md new file mode 100644 index 00000000000..60e641288cb --- /dev/null +++ b/tests/test-projects/crud-notifications/README.md @@ -0,0 +1,4 @@ +## THIS IS A TEST PROJECT + +The sole purpose of this project is to act as a fixture through which we run our admin-ui integration tests. +For useful and applicable examples of how to use keystone, please visit the [examples directory](https://github.com/keystonejs/keystone/tree/master/examples/) or visit our [docs](https://next.keystonejs.com). diff --git a/tests/test-projects/crud-notifications/keystone.ts b/tests/test-projects/crud-notifications/keystone.ts new file mode 100644 index 00000000000..87ce93e9453 --- /dev/null +++ b/tests/test-projects/crud-notifications/keystone.ts @@ -0,0 +1,23 @@ +import { config } from '@keystone-next/keystone/schema'; +import { lists } from './schema'; + +export default config({ + db: { + provider: 'sqlite', + url: process.env.DATABASE_URL || 'file:./test.db', + async onConnect(context) { + await context.lists.Task.createMany({ + data: [...Array.from(Array(50).keys())].map(key => { + return { label: `do not delete ${key}` }; + }), + }); + + await context.lists.Task.createMany({ + data: [...Array.from(Array(25).keys())].map(key => { + return { label: `deletable ${key}` }; + }), + }); + }, + }, + lists, +}); diff --git a/tests/test-projects/crud-notifications/package.json b/tests/test-projects/crud-notifications/package.json new file mode 100644 index 00000000000..585846b3c43 --- /dev/null +++ b/tests/test-projects/crud-notifications/package.json @@ -0,0 +1,22 @@ +{ + "name": "@keystone-next/test-projects-crud-notifications", + "version": "0.0.3", + "private": true, + "license": "MIT", + "scripts": { + "dev": "keystone-next dev", + "start": "keystone-next start", + "build": "keystone-next build" + }, + "dependencies": { + "@keystone-next/fields": "^14.0.0", + "@keystone-next/keystone": "^24.0.0" + }, + "devDependencies": { + "typescript": "^4.3.5" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "repository": "https://github.com/keystonejs/keystone/tree/master/tests/test-projects/crud-notifications" +} diff --git a/tests/test-projects/crud-notifications/schema.graphql b/tests/test-projects/crud-notifications/schema.graphql new file mode 100644 index 00000000000..e194b7cb406 --- /dev/null +++ b/tests/test-projects/crud-notifications/schema.graphql @@ -0,0 +1,329 @@ +type Task { + id: ID! + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: Person + finishBy: String +} + +enum TaskPriorityType { + low + medium + high +} + +input TaskWhereInput { + AND: [TaskWhereInput!] + OR: [TaskWhereInput!] + NOT: [TaskWhereInput!] + id: IDFilter + label: StringNullableFilter + priority: TaskPriorityTypeNullableFilter + isComplete: BooleanNullableFilter + assignedTo: PersonWhereInput + finishBy: DateTimeNullableFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter +} + +input TaskPriorityTypeNullableFilter { + equals: TaskPriorityType + in: [TaskPriorityType!] + notIn: [TaskPriorityType!] + not: TaskPriorityTypeNullableFilter +} + +input BooleanNullableFilter { + equals: Boolean + not: BooleanNullableFilter +} + +input DateTimeNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + not: DateTimeNullableFilter +} + +input TaskWhereUniqueInput { + id: ID +} + +input TaskOrderByInput { + id: OrderDirection + label: OrderDirection + priority: OrderDirection + isComplete: OrderDirection + finishBy: OrderDirection +} + +enum OrderDirection { + asc + desc +} + +input TaskUpdateInput { + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: PersonRelateToOneForUpdateInput + finishBy: String +} + +input PersonRelateToOneForUpdateInput { + create: PersonCreateInput + connect: PersonWhereUniqueInput + disconnect: Boolean +} + +input TaskUpdateArgs { + where: TaskWhereUniqueInput! + data: TaskUpdateInput! +} + +input TaskCreateInput { + label: String + priority: TaskPriorityType + isComplete: Boolean + assignedTo: PersonRelateToOneForCreateInput + finishBy: String +} + +input PersonRelateToOneForCreateInput { + create: PersonCreateInput + connect: PersonWhereUniqueInput +} + +type Person { + id: ID! + name: String + tasks( + where: TaskWhereInput! = {} + orderBy: [TaskOrderByInput!]! = [] + take: Int + skip: Int! = 0 + ): [Task!] + tasksCount(where: TaskWhereInput! = {}): Int +} + +input PersonWhereInput { + AND: [PersonWhereInput!] + OR: [PersonWhereInput!] + NOT: [PersonWhereInput!] + id: IDFilter + name: StringNullableFilter + tasks: TaskManyRelationFilter +} + +input TaskManyRelationFilter { + every: TaskWhereInput + some: TaskWhereInput + none: TaskWhereInput +} + +input PersonWhereUniqueInput { + id: ID +} + +input PersonOrderByInput { + id: OrderDirection + name: OrderDirection +} + +input PersonUpdateInput { + name: String + tasks: TaskRelateToManyForUpdateInput +} + +input TaskRelateToManyForUpdateInput { + disconnect: [TaskWhereUniqueInput!] + set: [TaskWhereUniqueInput!] + create: [TaskCreateInput!] + connect: [TaskWhereUniqueInput!] +} + +input PersonUpdateArgs { + where: PersonWhereUniqueInput! + data: PersonUpdateInput! +} + +input PersonCreateInput { + name: String + tasks: TaskRelateToManyForCreateInput +} + +input TaskRelateToManyForCreateInput { + create: [TaskCreateInput!] + connect: [TaskWhereUniqueInput!] +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON + @specifiedBy( + url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" + ) + +type Mutation { + createTask(data: TaskCreateInput!): Task + createTasks(data: [TaskCreateInput!]!): [Task] + updateTask(where: TaskWhereUniqueInput!, data: TaskUpdateInput!): Task + updateTasks(data: [TaskUpdateArgs!]!): [Task] + deleteTask(where: TaskWhereUniqueInput!): Task + deleteTasks(where: [TaskWhereUniqueInput!]!): [Task] + createPerson(data: PersonCreateInput!): Person + createPeople(data: [PersonCreateInput!]!): [Person] + updatePerson(where: PersonWhereUniqueInput!, data: PersonUpdateInput!): Person + updatePeople(data: [PersonUpdateArgs!]!): [Person] + deletePerson(where: PersonWhereUniqueInput!): Person + deletePeople(where: [PersonWhereUniqueInput!]!): [Person] +} + +type Query { + tasks( + where: TaskWhereInput! = {} + orderBy: [TaskOrderByInput!]! = [] + take: Int + skip: Int! = 0 + ): [Task!] + task(where: TaskWhereUniqueInput!): Task + tasksCount(where: TaskWhereInput! = {}): Int + people( + where: PersonWhereInput! = {} + orderBy: [PersonOrderByInput!]! = [] + take: Int + skip: Int! = 0 + ): [Person!] + person(where: PersonWhereUniqueInput!): Person + peopleCount(where: PersonWhereInput! = {}): Int + keystone: KeystoneMeta! +} + +type KeystoneMeta { + adminMeta: KeystoneAdminMeta! +} + +type KeystoneAdminMeta { + enableSignout: Boolean! + enableSessionItem: Boolean! + lists: [KeystoneAdminUIListMeta!]! + list(key: String!): KeystoneAdminUIListMeta +} + +type KeystoneAdminUIListMeta { + key: String! + itemQueryName: String! + listQueryName: String! + hideCreate: Boolean! + hideDelete: Boolean! + path: String! + label: String! + singular: String! + plural: String! + description: String + initialColumns: [String!]! + pageSize: Int! + labelField: String! + fields: [KeystoneAdminUIFieldMeta!]! + initialSort: KeystoneAdminUISort + isHidden: Boolean! +} + +type KeystoneAdminUIFieldMeta { + path: String! + label: String! + isOrderable: Boolean! + fieldMeta: JSON + viewsIndex: Int! + customViewsIndex: Int + createView: KeystoneAdminUIFieldMetaCreateView! + listView: KeystoneAdminUIFieldMetaListView! + itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + search: QueryMode +} + +type KeystoneAdminUIFieldMetaCreateView { + fieldMode: KeystoneAdminUIFieldMetaCreateViewFieldMode! +} + +enum KeystoneAdminUIFieldMetaCreateViewFieldMode { + edit + hidden +} + +type KeystoneAdminUIFieldMetaListView { + fieldMode: KeystoneAdminUIFieldMetaListViewFieldMode! +} + +enum KeystoneAdminUIFieldMetaListViewFieldMode { + read + hidden +} + +type KeystoneAdminUIFieldMetaItemView { + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! +} + +enum KeystoneAdminUIFieldMetaItemViewFieldMode { + edit + read + hidden +} + +enum QueryMode { + default + insensitive +} + +type KeystoneAdminUISort { + field: String! + direction: KeystoneAdminUISortDirection! +} + +enum KeystoneAdminUISortDirection { + ASC + DESC +} diff --git a/tests/test-projects/crud-notifications/schema.prisma b/tests/test-projects/crud-notifications/schema.prisma new file mode 100644 index 00000000000..a1efaced2f7 --- /dev/null +++ b/tests/test-projects/crud-notifications/schema.prisma @@ -0,0 +1,27 @@ +datasource sqlite { + url = env("DATABASE_URL") + provider = "sqlite" +} + +generator client { + provider = "prisma-client-js" + output = "node_modules/.prisma/client" +} + +model Task { + id String @id @default(cuid()) + label String? + priority String? + isComplete Boolean? + assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) + assignedToId String? @map("assignedTo") + finishBy DateTime? + + @@index([assignedToId]) +} + +model Person { + id String @id @default(cuid()) + name String? + tasks Task[] @relation("Task_assignedTo") +} \ No newline at end of file diff --git a/tests/test-projects/crud-notifications/schema.ts b/tests/test-projects/crud-notifications/schema.ts new file mode 100644 index 00000000000..8cc4f22288c --- /dev/null +++ b/tests/test-projects/crud-notifications/schema.ts @@ -0,0 +1,38 @@ +import { createSchema, list } from '@keystone-next/keystone/schema'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; +import { select } from '@keystone-next/fields'; + +export const lists = createSchema({ + Task: list({ + access: { + delete: async ({ itemId, context }) => { + const item: any = await context.lists.Task.findOne({ + where: { id: itemId }, + query: 'label', + }); + const matchString = item.label.replace(/([\d])+/g, '').trim(); + return !['do not delete', 'do not destroy', 'do not kill'].includes(matchString); + }, + }, + fields: { + label: text({ isRequired: true }), + priority: select({ + dataType: 'enum', + options: [ + { label: 'Low', value: 'low' }, + { label: 'Medium', value: 'medium' }, + { label: 'High', value: 'high' }, + ], + }), + isComplete: checkbox(), + assignedTo: relationship({ ref: 'Person.tasks', many: false }), + finishBy: timestamp(), + }, + }), + Person: list({ + fields: { + name: text({ isRequired: true }), + tasks: relationship({ ref: 'Task.assignedTo', many: true }), + }, + }), +}); diff --git a/yarn.lock b/yarn.lock index 034e47534e3..0bebeff4aac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,24 +2,23 @@ # yarn lockfile v1 -"@apollo/client@3.3.21", "@apollo/client@^3.1.3": - version "3.3.21" - resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.3.21.tgz#2862baa4e1ced8c5e89ebe6fc52877fc64a726aa" - integrity sha512-RAmZReFuKCKx0Rs5C0nVJwKomAHUHn+gGP/YvbEsXQWu0sXoncEUZa71UqlfCPVXa/0MkYOIbCXSQdOcuRrHgw== +"@apollo/client@^3.1.3", "@apollo/client@^3.4.8": + version "3.4.8" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.4.8.tgz#66d06dc1784d07d46731b3bda546046f8c280b74" + integrity sha512-/cNqTSwc2Dw8q6FDDjdd30+yvhP7rI0Fvl3Hbro0lTtFuhzkevfNyQaI2jAiOrjU6Jc0RbanxULaNrX7UmvjSQ== dependencies: "@graphql-typed-document-node/core" "^3.0.0" - "@types/zen-observable" "^0.8.0" "@wry/context" "^0.6.0" "@wry/equality" "^0.5.0" - fast-json-stable-stringify "^2.0.0" - graphql-tag "^2.12.0" + "@wry/trie" "^0.3.0" + graphql-tag "^2.12.3" hoist-non-react-statics "^3.3.2" - optimism "^0.16.0" + optimism "^0.16.1" prop-types "^15.7.2" symbol-observable "^4.0.0" - ts-invariant "^0.8.0" - tslib "^1.10.0" - zen-observable "^0.8.14" + ts-invariant "^0.9.0" + tslib "^2.3.0" + zen-observable-ts "^1.1.0" "@apollo/protobufjs@1.2.2": version "1.2.2" @@ -79,25 +78,25 @@ dependencies: "@babel/highlight" "^7.14.5" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.5", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.9.tgz#ac7996ceaafcf8f410119c8af0d1db4cf914a210" - integrity sha512-p3QjZmMGHDGdpcwEYYWu7i7oJShJvtgMjJeb0W95PPhSm++3lm8YXYOh45Y6iCN9PkZLTZ7CIX5nFrp7pw7TXw== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.14.8", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.7.7": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010" - integrity sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q== +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.15.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.7.7": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8" + integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw== dependencies: "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.14.8" - "@babel/helper-compilation-targets" "^7.14.5" - "@babel/helper-module-transforms" "^7.14.8" + "@babel/generator" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@babel/helper-module-transforms" "^7.15.0" "@babel/helpers" "^7.14.8" - "@babel/parser" "^7.14.8" + "@babel/parser" "^7.15.0" "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -105,12 +104,12 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.14.8", "@babel/generator@^7.14.9", "@babel/generator@^7.7.2": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.9.tgz#23b19c597d38b4f7dc2e3fe42a69c88d9ecfaa16" - integrity sha512-4yoHbhDYzFa0GLfCzLp5GxH7vPPMAHdZjyE7M/OajM9037zhx0rf+iNsJwp4PT0MSFpwjG7BsHEbPkBQpZ6cYA== +"@babel/generator@^7.15.0", "@babel/generator@^7.7.2": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15" + integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== dependencies: - "@babel/types" "^7.14.9" + "@babel/types" "^7.15.0" jsesc "^2.5.1" source-map "^0.5.0" @@ -129,26 +128,26 @@ "@babel/helper-explode-assignable-expression" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz#7a99c5d0967911e972fe2c3411f7d5b498498ecf" - integrity sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818" + integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A== dependencies: - "@babel/compat-data" "^7.14.5" + "@babel/compat-data" "^7.15.0" "@babel/helper-validator-option" "^7.14.5" browserslist "^4.16.6" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.14.6": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.8.tgz#a6f8c3de208b1e5629424a9a63567f56501955fc" - integrity sha512-bpYvH8zJBWzeqi1o+co8qOrw+EXzQ/0c74gVmY205AWXy9nifHrOg77y+1zwxX5lXE7Icq4sPlSQ4O2kWBrteQ== +"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz#c9a137a4d137b2d0e2c649acf536d7ba1a76c0f7" + integrity sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q== dependencies: "@babel/helper-annotate-as-pure" "^7.14.5" "@babel/helper-function-name" "^7.14.5" - "@babel/helper-member-expression-to-functions" "^7.14.7" + "@babel/helper-member-expression-to-functions" "^7.15.0" "@babel/helper-optimise-call-expression" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" "@babel/helper-split-export-declaration" "^7.14.5" "@babel/helper-create-regexp-features-plugin@^7.14.5": @@ -203,12 +202,12 @@ dependencies: "@babel/types" "^7.14.5" -"@babel/helper-member-expression-to-functions@^7.14.5", "@babel/helper-member-expression-to-functions@^7.14.7": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz#97e56244beb94211fe277bd818e3a329c66f7970" - integrity sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA== +"@babel/helper-member-expression-to-functions@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b" + integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg== dependencies: - "@babel/types" "^7.14.5" + "@babel/types" "^7.15.0" "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5": version "7.14.5" @@ -217,19 +216,19 @@ dependencies: "@babel/types" "^7.14.5" -"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.14.8": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz#d4279f7e3fd5f4d5d342d833af36d4dd87d7dc49" - integrity sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA== +"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08" + integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg== dependencies: "@babel/helper-module-imports" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" "@babel/helper-simple-access" "^7.14.8" "@babel/helper-split-export-declaration" "^7.14.5" - "@babel/helper-validator-identifier" "^7.14.8" + "@babel/helper-validator-identifier" "^7.14.9" "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" "@babel/helper-optimise-call-expression@^7.14.5": version "7.14.5" @@ -252,17 +251,17 @@ "@babel/helper-wrap-function" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/helper-replace-supers@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz#0ecc0b03c41cd567b4024ea016134c28414abb94" - integrity sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow== +"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4" + integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.14.5" + "@babel/helper-member-expression-to-functions" "^7.15.0" "@babel/helper-optimise-call-expression" "^7.14.5" - "@babel/traverse" "^7.14.5" - "@babel/types" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" -"@babel/helper-simple-access@^7.14.5", "@babel/helper-simple-access@^7.14.8": +"@babel/helper-simple-access@^7.14.8": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924" integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg== @@ -283,7 +282,7 @@ dependencies: "@babel/types" "^7.14.5" -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.8", "@babel/helper-validator-identifier@^7.14.9": +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": version "7.14.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== @@ -304,13 +303,13 @@ "@babel/types" "^7.14.5" "@babel/helpers@^7.14.8": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.8.tgz#839f88f463025886cff7f85a35297007e2da1b77" - integrity sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357" + integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g== dependencies: "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": version "7.14.5" @@ -321,10 +320,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.14.9", "@babel/parser@^7.7.2": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.9.tgz#596c1ad67608070058ebf8df50c1eaf65db895a4" - integrity sha512-RdUTOseXJ8POjjOeEBEvNMIZU/nm4yu2rufRkcibzkkg7DmQvXU8v3M4Xk9G7uuI86CDGkKcuDWgioqZm+mScQ== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.7.2": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862" + integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": version "7.14.5" @@ -519,7 +518,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.14.5": +"@babel/plugin-syntax-jsx@7.14.5", "@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw== @@ -613,9 +612,9 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-block-scoping@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz#8cc63e61e50f42e078e6f09be775a75f23ef9939" - integrity sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" @@ -707,14 +706,14 @@ "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.14.5", "@babel/plugin-transform-modules-commonjs@^7.7.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97" - integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A== +"@babel/plugin-transform-modules-commonjs@^7.15.0", "@babel/plugin-transform-modules-commonjs@^7.7.5": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz#3305896e5835f953b5cdb363acd9e8c2219a5281" + integrity sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig== dependencies: - "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-module-transforms" "^7.15.0" "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.14.5" + "@babel/helper-simple-access" "^7.14.8" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.14.5": @@ -773,9 +772,9 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-react-display-name@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.5.tgz#baa92d15c4570411301a85a74c13534873885b65" - integrity sha512-07aqY1ChoPgIxsuDviptRpVkWCSbXWmzQqcgy65C6YSFOfPFvb/DX3bBRHh7pCd/PMEEYHYWUTSVkCbkVainYQ== + version "7.15.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.15.1.tgz#6aaac6099f1fcf6589d35ae6be1b6e10c8c602b9" + integrity sha512-yQZ/i/pUCJAHI/LbtZr413S3VT26qNrEm0M5RRxQJA947/YNYwbZbBaXGDrq6CG5QsZycI1VIP6d7pQaBfP+8Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" @@ -819,10 +818,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-runtime@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523" - integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg== +"@babel/plugin-transform-runtime@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3" + integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw== dependencies: "@babel/helper-module-imports" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" @@ -867,12 +866,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-typescript@^7.14.5": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.14.6.tgz#6e9c2d98da2507ebe0a883b100cde3c7279df36c" - integrity sha512-XlTdBq7Awr4FYIzqhmYY80WN0V0azF74DMPyFqVHBvf81ZUgc4X7ZOpx6O8eLDK6iM5cCQzeyJw0ynTaefixRA== +"@babel/plugin-transform-typescript@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.0.tgz#553f230b9d5385018716586fc48db10dd228eb7e" + integrity sha512-WIIEazmngMEEHDaPTx0IZY48SaAmjVWe3TRSX7cmJXn0bEv9midFzAjxiruOWYIVf5iQ10vFx7ASDpgEO08L5w== dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.6" + "@babel/helper-create-class-features-plugin" "^7.15.0" "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript" "^7.14.5" @@ -891,13 +890,13 @@ "@babel/helper-create-regexp-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.9.tgz#4a3bbbd745f20e9121d5925170bef040a21b7819" - integrity sha512-BV5JvCwBDebkyh67bPKBYVCC6gGw0MCzU6HfKe5Pm3upFpPVqiC/hB33zkOe0tVdAzaMywah0LSXQeD9v/BYdQ== +"@babel/preset-env@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.0.tgz#e2165bf16594c9c05e52517a194bf6187d6fe464" + integrity sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q== dependencies: - "@babel/compat-data" "^7.14.9" - "@babel/helper-compilation-targets" "^7.14.5" + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5" @@ -945,7 +944,7 @@ "@babel/plugin-transform-literals" "^7.14.5" "@babel/plugin-transform-member-expression-literals" "^7.14.5" "@babel/plugin-transform-modules-amd" "^7.14.5" - "@babel/plugin-transform-modules-commonjs" "^7.14.5" + "@babel/plugin-transform-modules-commonjs" "^7.15.0" "@babel/plugin-transform-modules-systemjs" "^7.14.5" "@babel/plugin-transform-modules-umd" "^7.14.5" "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" @@ -963,7 +962,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.14.5" "@babel/plugin-transform-unicode-regex" "^7.14.5" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.14.9" + "@babel/types" "^7.15.0" babel-plugin-polyfill-corejs2 "^0.2.2" babel-plugin-polyfill-corejs3 "^0.2.2" babel-plugin-polyfill-regenerator "^0.2.2" @@ -993,19 +992,19 @@ "@babel/plugin-transform-react-jsx-development" "^7.14.5" "@babel/plugin-transform-react-pure-annotations" "^7.14.5" -"@babel/preset-typescript@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.14.5.tgz#aa98de119cf9852b79511f19e7f44a2d379bcce0" - integrity sha512-u4zO6CdbRKbS9TypMqrlGH7sd2TAJppZwn3c/ZRLeO/wGsbddxgbPDUZVNrie3JWYLQ9vpineKlsrWFvO6Pwkw== +"@babel/preset-typescript@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945" + integrity sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-transform-typescript" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.15.0" "@babel/runtime-corejs3@^7.10.2": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.14.9.tgz#fb21b1cf11650dcb8fcf4de2e6b3b8cf411da3f3" - integrity sha512-64RiH2ON4/y8qYtoa8rUiyam/tUVyGqRyNYhe+vCRGmjnV4bUlZvY+mwd0RrmLoCpJpdq3RsrNqKb7SJdw/4kw== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz#28754263988198f2a928c09733ade2fb4d28089d" + integrity sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A== dependencies: core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" @@ -1017,10 +1016,10 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" - integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== dependencies: regenerator-runtime "^0.13.4" @@ -1033,21 +1032,29 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8", "@babel/traverse@^7.7.2": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.9.tgz#016126b331210bf06fff29d52971eef8383e556f" - integrity sha512-bldh6dtB49L8q9bUyB7bC20UKgU+EFDwKJylwl234Kv+ySZeMD31Xeht6URyueQ6LrRRpF2tmkfcZooZR9/e8g== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.0", "@babel/traverse@^7.7.2": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98" + integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw== dependencies: "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.14.9" + "@babel/generator" "^7.15.0" "@babel/helper-function-name" "^7.14.5" "@babel/helper-hoist-variables" "^7.14.5" "@babel/helper-split-export-declaration" "^7.14.5" - "@babel/parser" "^7.14.9" - "@babel/types" "^7.14.9" + "@babel/parser" "^7.15.0" + "@babel/types" "^7.15.0" debug "^4.1.0" globals "^11.1.0" +"@babel/types@7.15.0", "@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.14.9", "@babel/types@^7.15.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" + integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + "@babel/types@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" @@ -1057,14 +1064,6 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.14.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.9.tgz#f2b19c3f2f77c5708d67fe8f6046e9cea2b5036d" - integrity sha512-u0bLTnv3DFHeaQLYzb7oRJ1JHr1sv/SYDM7JSqHFFLwXG1wTZRughxFI5NCP8qBEo1rVVsn7Yg2Lvw49nne/Ow== - dependencies: - "@babel/helper-validator-identifier" "^7.14.9" - to-fast-properties "^2.0.0" - "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1282,9 +1281,9 @@ prettier "^1.19.1" "@corex/deepmerge@^2.6.20": - version "2.6.20" - resolved "https://registry.yarnpkg.com/@corex/deepmerge/-/deepmerge-2.6.20.tgz#a72d1cb5a101fd11160815b96f499a588362ba5b" - integrity sha512-oZZxwDtV0bf8VPcSIhZPvdBFUkVIC8zRblUjrrVAsbGRiqUuZJfoXw2M6NDiIXWcUCfOqbkFND6Yf3b9ej9AjA== + version "2.6.34" + resolved "https://registry.yarnpkg.com/@corex/deepmerge/-/deepmerge-2.6.34.tgz#8dd084f2bcc9cf54f6b1210a1aebd25206de2a84" + integrity sha512-5l3bQRGOoCJ1nYTxEaOW/MRuwNDq32KYatWO5rwOlOzxY4beVCrxDBaDBX5wpDn0PYm0QAul/vAC9GDHShEbTw== "@cypress/listr-verbose-renderer@^0.4.1": version "0.4.1" @@ -1416,15 +1415,15 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== -"@emotion/react@^11.1.1", "@emotion/react@^11.4.0": - version "11.4.0" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.4.0.tgz#2465ad7b073a691409b88dfd96dc17097ddad9b7" - integrity sha512-4XklWsl9BdtatLoJpSjusXhpKv9YVteYKh9hPKP1Sxl+mswEFoUe0WtmtWjxEjkA51DQ2QRMCNOvKcSlCQ7ivg== +"@emotion/react@^11.1.1", "@emotion/react@^11.4.1": + version "11.4.1" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.4.1.tgz#a1b0b767b5bad57515ffb0cad9349614d27f4d57" + integrity sha512-pRegcsuGYj4FCdZN6j5vqCALkNytdrKw3TZMekTzNXixRg4wkLsU5QEaBG5LC6l01Vppxlp7FE3aTHpIG5phLg== dependencies: "@babel/runtime" "^7.13.10" "@emotion/cache" "^11.4.0" "@emotion/serialize" "^1.0.2" - "@emotion/sheet" "^1.0.1" + "@emotion/sheet" "^1.0.2" "@emotion/utils" "^1.0.0" "@emotion/weak-memoize" "^0.2.5" hoist-non-react-statics "^3.3.1" @@ -1466,10 +1465,10 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== -"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698" - integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g== +"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.2.tgz#1d9ffde531714ba28e62dac6a996a8b1089719d0" + integrity sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw== "@emotion/stylis@0.8.5": version "0.8.5" @@ -1511,36 +1510,35 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@graphql-tools/merge@6.2.16", "@graphql-tools/merge@^6.2.16": - version "6.2.16" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-6.2.16.tgz#5dd5f582075c21ef4d74ef84dfcc4e8d0c2db186" - integrity sha512-KjZ1pppzKcr2Uspgb53p8uw5yhWVuGIL+sEroar7vLsClSsuiGib8OKVICAGWjC9wrCxGaL9SjJGavfXpJMQIg== +"@graphql-tools/merge@8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.0.1.tgz#4cb94998e7c61abc6ebec54edca5c19f06c3330d" + integrity sha512-YAozogbjC2Oun+UcwG0LZFumhlCiHBmqe68OIf7bqtBdp4pbPAiVuK/J9oJqRVJmzvUqugo6RD9zz1qDTKZaiQ== dependencies: - "@graphql-tools/schema" "^8.0.1" - "@graphql-tools/utils" "8.0.1" + "@graphql-tools/utils" "8.1.1" tslib "~2.3.0" -"@graphql-tools/schema@^8.0.1": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.0.1.tgz#178b734f3784e632a76bdd144ffa8a32169a6f4a" - integrity sha512-QG2HGLJjmsNc1wcj+rwZTEArgfMp7rsrb8iVq4P8ce1mDYAt6kRV6bLyPVb9q/j8Ik2zBc/B/Y1jPsnAVUHwdA== +"@graphql-tools/schema@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.1.1.tgz#5de95a8f6cedaf91fa2f9e9e7fa9fae1d27a7c4f" + integrity sha512-u+0kxPtuP+GcKnGNt459Ob7iIpzesIJeJTmPPailaG7ZhB5hkXIizl4uHrzEIAh2Ja1P/VA8sEBYpu1N0n6Mmg== dependencies: - "@graphql-tools/merge" "6.2.16" - "@graphql-tools/utils" "8.0.1" + "@graphql-tools/merge" "8.0.1" + "@graphql-tools/utils" "8.1.1" tslib "~2.3.0" value-or-promise "1.0.10" -"@graphql-tools/utils@8.0.1": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.0.1.tgz#bf09e8d6d17c4a0830f0fbf2c69dd725de19058c" - integrity sha512-gjQk6sht4b0/hcG+QEVxfMyO8bn5tuU1nIOVhQ4whgFaUmrnb3hx2mwzz1EJzfIOAuHKE8tY0lu6jt3bGTD4yg== +"@graphql-tools/utils@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.1.1.tgz#2ef056a1d6e1e909085e1115d3bb48f890c2a2b6" + integrity sha512-QbFNoBmBiZ+ej4y6mOv8Ba4lNhcrTEKXAhZ0f74AhdEXi7b9xbGUH/slO5JaSyp85sGQYIPmxjRPpXBjLklbmw== dependencies: tslib "~2.3.0" -"@graphql-ts/schema@0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@graphql-ts/schema/-/schema-0.1.2.tgz#71b04cc88ff61f5c19a81ac70f878b1e36f617da" - integrity sha512-ZP4Nj70B18q1Y7B4WHeJR5gMyoH8oX9umnpmT9gu6kUD9rmTZfqHE9cGHRisw+ZOlWBnx6rPrx0BmUROFQFORA== +"@graphql-ts/schema@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@graphql-ts/schema/-/schema-0.2.0.tgz#1fc11a985cd5b0534de6616abcf05b0b493b8252" + integrity sha512-4hLQW5RfJkSkqia3Tl/LRVjsIGziTN/fHsUEuSIg1quD0y3pPpQxisDAIt4nkevY53q+JuGSVG1isJz+v8Ym/g== dependencies: "@babel/runtime" "^7.9.2" @@ -1794,17 +1792,6 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - "@jest/types@^27.0.6": version "27.0.6" resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.0.6.tgz#9a992bc517e0c49f035938b8549719c2de40706b" @@ -1914,21 +1901,36 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@napi-rs/triples@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c" + integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA== + "@next/env@10.2.3": version "10.2.3" resolved "https://registry.yarnpkg.com/@next/env/-/env-10.2.3.tgz#ede3bbe68cec9939c37168ea2077f9adbc68334e" integrity sha512-uBOjRBjsWC4C8X3DfmWWP6ekwLnf2JCCwQX9KVnJtJkqfDsv1yQPakdOEwvJzXQc3JC/v5KKffYPVmV2wHXCgQ== -"@next/mdx@^10.2.3": - version "10.2.3" - resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-10.2.3.tgz#226d25530e4b98af3a200be3e2616beebf81b56c" - integrity sha512-hseekptFqOCxLbdaNDS/yelaG2Q2uaNDilnRjq8Uv/LWHuZ9F2cp7ndwTolW9acJsbDedamKRMgdw4V2Fz0pUA== +"@next/env@11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@next/env/-/env-11.1.0.tgz#cae83d8e0a65aa9f2af3368f8269ffd9d911746a" + integrity sha512-zPJkMFRenSf7BLlVee8987G0qQXAhxy7k+Lb/5hLAGkPVHAHm+oFFeL+2ipbI2KTEFlazdmGY0M+AlLQn7pWaw== + +"@next/mdx@^11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-11.1.0.tgz#79d6d20e0906e81c07aed0f8286d58530d051be6" + integrity sha512-X+NwSByGr9HuPkGs1nrzhmJ5qqQbv6CpEA3dJKEYHaDe7YzEUCM00Y7abxOzowXhUXeDdAHJ7IeIV4GZMhdcpg== "@next/polyfill-module@10.2.3": version "10.2.3" resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-10.2.3.tgz#5a29f50c3ce3a56b8268d3b8331c691d8039467a" integrity sha512-OkeY4cLhzfYbXxM4fd+6V4s5pTPuyfKSlavItfNRA6PpS7t1/R6YjO7S7rB8tu1pbTGuDHGIdE1ioDv15bAbDQ== +"@next/polyfill-module@11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-11.1.0.tgz#ee6b9117a1f9bb137479dfa51d5a9e38e066a62f" + integrity sha512-64EgW8SzJRQls2yJ5DkuljRxgE24o2kYtX/ghTkPUJYsfidHMWzQGwg26IgRbb/uHqTd1G0W5UkKag+Nt8TWaQ== + "@next/react-dev-overlay@10.2.3": version "10.2.3" resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-10.2.3.tgz#95313d10a8848f6c7b9e31ae3bd2a3627d136841" @@ -1946,11 +1948,40 @@ stacktrace-parser "0.1.10" strip-ansi "6.0.0" +"@next/react-dev-overlay@11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-11.1.0.tgz#8d4e8020a4cbdacbca431a0bf40c4d28187083af" + integrity sha512-h+ry0sTk1W3mJw+TwEf91aqLbBJ5oqAsxfx+QryqEItNtfW6zLSSjxkyTYTqX8DkgSssQQutQfATkzBVgOR+qQ== + dependencies: + "@babel/code-frame" "7.12.11" + anser "1.4.9" + chalk "4.0.0" + classnames "2.2.6" + css.escape "1.5.1" + data-uri-to-buffer "3.0.1" + platform "1.3.6" + shell-quote "1.7.2" + source-map "0.8.0-beta.0" + stacktrace-parser "0.1.10" + strip-ansi "6.0.0" + "@next/react-refresh-utils@10.2.3": version "10.2.3" resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-10.2.3.tgz#2f3e42fe6680798f276e3621345c2886b231348b" integrity sha512-qtBF56vPC6d6a8p7LYd0iRjW89fhY80kAIzmj+VonvIGjK/nymBjcFUhbKiMFqlhsarCksnhwX+Zmn95Dw9qvA== +"@next/react-refresh-utils@11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-11.1.0.tgz#60c3c7b127a5dab8b0a2889a7dcf8a90d2c4e592" + integrity sha512-g5DtFTpLTGa36iy9DuZawtJeitI11gysFGKPQQqy+mNbSFazguArcJ10gAYFlbqpIi4boUamWNI5mAoSPx3kog== + +"@node-rs/helper@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@node-rs/helper/-/helper-1.2.1.tgz#e079b05f21ff4329d82c4e1f71c0290e4ecdc70c" + integrity sha512-R5wEmm8nbuQU0YGGmYVjEc0OHtYsuXdpRG+Ut/3wZ9XAvQWyThN08bTh2cBJgoZxHQUPtvRfeQuxcAgLuiBISg== + dependencies: + "@napi-rs/triples" "^1.0.3" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1989,10 +2020,10 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.14.0.tgz#c67fc20a4d891447ca1a855d7d70fa79a3533001" integrity sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw== -"@popperjs/core@^2.9.2": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353" - integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q== +"@popperjs/core@^2.9.3": + version "2.9.3" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.3.tgz#8b68da1ebd7fc603999cf6ebee34a4899a14b88e" + integrity sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ== "@preconstruct/cli@2.1.0": version "2.1.0" @@ -2059,20 +2090,12 @@ resolved "https://registry.yarnpkg.com/@preconstruct/next/-/next-3.0.0.tgz#71781cbaecd011f43e456a149817094a43e4755f" integrity sha512-G90cyJX9w4Zr3Bt/j2fURgDhsJb5+agqf4YUgrvDe3Dyvbbssy9a6d0tzLH0ehfa2Osxw/EEhQb+W4X+v/x06A== -"@prisma/client@2.28.0": - version "2.28.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.28.0.tgz#6cd91a3c2757814a9454ea23d7e33cd2ff3952db" - integrity sha512-iwdxpy0Nz8N40MnhdlRvhZOBk8+GawpEsY5FU8Tfw1k9rvIeTAi+wBHrqhY8bXq6pneZkzrdQ1Hj3tqkrbRmoQ== - dependencies: - "@prisma/engines-version" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - -"@prisma/debug@2.27.0": - version "2.27.0" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-2.27.0.tgz#ae4c565813011c6e6d29fbe948672f39bc4899d3" - integrity sha512-Et01S4RoLnQP9u547dCp74aSnLWTu0akfBCzF4zQZsbEdw7wXLttrcvbcYKr+KhpfF5Xu291UP/Kaxg0aj8o4w== +"@prisma/client@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.29.1.tgz#a7b91c9644800de4e00b2f7c3789ff4bae42b3d6" + integrity sha512-GhieSvHGPIV5IwRYIkJ4FrGSNfX18lPhFtlyVWxhvX0ocdy8oTnjNZVTFgGxB6qVmJIUpH1HsckAzIoAX689IA== dependencies: - debug "4.3.2" - ms "^2.1.3" + "@prisma/engines-version" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" "@prisma/debug@2.28.0": version "2.28.0" @@ -2082,41 +2105,50 @@ debug "4.3.2" ms "^2.1.3" -"@prisma/engine-core@2.28.0": - version "2.28.0" - resolved "https://registry.yarnpkg.com/@prisma/engine-core/-/engine-core-2.28.0.tgz#9e1dcd11b88c55e48af292c272258a10cba8391f" - integrity sha512-J8lbA85PFpcwm2+u6bQHLomnbsrEnsJkq1PFrplthvJDlOK/tOl9CDuxU2IriJ9KHd+0Y0qaqcGmO+xXfFu3HA== +"@prisma/debug@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-2.29.1.tgz#f5a6b480ea063844c6b1b40974402be8bda05fad" + integrity sha512-8OAh4ozVCvlcZU1HaP7QTWIA6Aqzs98nYgTYrxjDLqXJcytIvpIjHxfgqKhuPQ8MTkUm9cI5TJGswwcjJt0/0g== dependencies: - "@prisma/debug" "2.28.0" - "@prisma/engines" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - "@prisma/generator-helper" "2.28.0" - "@prisma/get-platform" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - chalk "^4.0.0" - execa "^5.0.0" - get-stream "^6.0.0" - indent-string "^4.0.0" - new-github-issue-url "^0.2.1" - p-retry "^4.2.0" - terminal-link "^2.1.1" + "@types/debug" "4.1.7" + debug "4.3.2" + ms "2.1.3" + +"@prisma/engine-core@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/engine-core/-/engine-core-2.29.1.tgz#9fdb1fddea6d650a97ae1d86e8264d4b95dbe364" + integrity sha512-vbZNry916sErWIagF62kASy665Pe9xDYdOQuJ9Njg90sApg4qHPAmDqRC5cf4wQzWOnhnenmWC7AjUfQKrrFiQ== + dependencies: + "@prisma/debug" "2.29.1" + "@prisma/engines" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@prisma/generator-helper" "2.29.1" + "@prisma/get-platform" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + chalk "4.1.2" + execa "5.1.1" + get-stream "6.0.1" + indent-string "4.0.0" + new-github-issue-url "0.2.1" + p-retry "4.6.1" + terminal-link "2.1.1" undici "3.3.6" -"@prisma/engines-version@2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27": - version "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27.tgz#6dbccdce64f792dbc21c99daef80ec03020c110d" - integrity sha512-BWTvF1mGxjG8EtG215uhxdeW5Uf5aiH4xhfzcFPFC3Ux5BdEM1uEBrLIixX67mI+ZNhqNZSBPf0DSf2I1IsaZw== +"@prisma/engines-version@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": + version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#96db92f09714d4dd2a5e21054c28bd1c0820fa77" + integrity sha512-BU1DNNDhdzqjHtycpUzDrU8+jf6ZY+fbXvCV/rbqG+0JifljlIo4vbkHDMg97gBi1Do8pTLZGlTH16FlniKgAg== -"@prisma/engines@2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27": - version "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27.tgz#5a563ead03405fc6ccb33fe48f8b3a8712be391e" - integrity sha512-r3/EnwKjbu2qz13I98hPQQdeFrOEcwdjlrB9CcoSoqRCjSHLnpdVMUvRfYuRKIoEF7p941R7/Fov0/CxOLF/MQ== +"@prisma/engines@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": + version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#0a44a6dcbee7e0a2850ea086675a8a4f4d627f9d" + integrity sha512-cgEoGK3dmKZkMp/sRbL8TsuVS50rHXYBHk2NY18DPUGr5//4ICno46EjzlayqAFVak8J6RtWZEs+8tE8j8frAQ== -"@prisma/fetch-engine@2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27": - version "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27.tgz#41de37f756e59dab8d50ecb5c7cdd521da19a689" - integrity sha512-o30L0+IrnK8ncT5qypnMW0AagpdTGCDL9eitDp59PA4KTPcfyusgcjcIgPm0qfcsiOrbvriBYCDmjXhNKNfaMA== +"@prisma/fetch-engine@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": + version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#de40f3bd761f3da1f2e0e0af027514c845f58264" + integrity sha512-HsTHffo2xg0rZchdqWJHDvl7JaOi2U1rDockKYAYPf3grGZ14AnJ/ZVP292xMm0IiGLkb5YE3qkI5SKoGEUqMw== dependencies: - "@prisma/debug" "2.27.0" - "@prisma/get-platform" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" + "@prisma/debug" "2.28.0" + "@prisma/get-platform" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" chalk "^4.0.0" execa "^5.0.0" find-cache-dir "^3.3.1" @@ -2133,83 +2165,83 @@ temp-dir "^2.0.0" tempy "^1.0.0" -"@prisma/generator-helper@2.28.0": - version "2.28.0" - resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-2.28.0.tgz#5444f3c5bf8334f234ba25ca3c2360408e7a1495" - integrity sha512-KaDFroGSVfDJBQRoKdXmDvP93Ukj3gI9DVjtABlQFl5FII4VCtsOix76VK+h/Hej4p0yrU6LCCU24Jmw4Enksg== - dependencies: - "@prisma/debug" "2.28.0" - "@types/cross-spawn" "^6.0.1" - chalk "^4.0.0" - cross-spawn "^7.0.2" - -"@prisma/get-platform@2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27": - version "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27.tgz#52904ae6b982fa162202220f7e03554daeacabca" - integrity sha512-OdTubLy4lVRYNvF3N9eODWxLxUhgh2oapDVvdMO3YmHQSeYQzzHHhYHBKoUY9zpCCAbAPBik+YIXgimJp3lqQQ== +"@prisma/generator-helper@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-2.29.1.tgz#7bd984f649ba830d11fdd514f8781c92a2782e41" + integrity sha512-rba/mfxv1JtbAm51yXipYY7DVYB4L2DVVnnXOvSAhAqDLUVylT68WxLXQKiSBxNAlks5ngD2DeaH6qpGi+XnYw== dependencies: - "@prisma/debug" "2.27.0" + "@prisma/debug" "2.29.1" + "@types/cross-spawn" "6.0.2" + chalk "4.1.2" + cross-spawn "7.0.3" -"@prisma/migrate@2.28.0": - version "2.28.0" - resolved "https://registry.yarnpkg.com/@prisma/migrate/-/migrate-2.28.0.tgz#7923a463cb58ac1eb32d93cf0a828da3744c81a2" - integrity sha512-vWE8OSKDPIlfW8bJU98xm11s8nKtve77M7N8oJlktYL8pENHnSYoWcDynq/RZcZlf0Zb74OOmOJ7Qh6/WBO3DA== +"@prisma/get-platform@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": + version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#78e9200abdfa15446d4830c101e5b2d692bef7ab" + integrity sha512-eEuXFcELlo8bAszQOz3YOyVpoKMjD/RSml29P51WFaDaHZaudfqV6OkSpMV2Qchcyg6neI1mvT+0acutBpNXTw== dependencies: "@prisma/debug" "2.28.0" - "@prisma/get-platform" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - "@sindresorhus/slugify" "^1.1.0" - execa "^5.0.0" - global-dirs "^3.0.0" - has-yarn "^2.1.0" - indent-string "^4.0.0" - log-update "^4.0.0" - new-github-issue-url "^0.2.1" - open "^7.0.3" - pkg-up "^3.1.0" - prompts "^2.3.2" - resolve-pkg "^2.0.0" - strip-ansi "^6.0.0" - strip-indent "^3.0.0" -"@prisma/sdk@2.28.0": - version "2.28.0" - resolved "https://registry.yarnpkg.com/@prisma/sdk/-/sdk-2.28.0.tgz#8c2f3c3fbcc53bfb1eb68944fd023e8870a5be7c" - integrity sha512-JlZiuREFWoElZHbH4aJ5wqij1qQGQGnnu6h+hULX8ZQjzwreyfyQ36QTGNak6FPeR4cjjIpOsQqRxvKvhETalw== +"@prisma/migrate@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/migrate/-/migrate-2.29.1.tgz#dc0be465ff89cdce4435c90938b25cd453b842c7" + integrity sha512-hIupZVHlHNByxCV+k7I5X3GaxV6pNYcQgPGbPphK8zOX0gDbRJIlJZ+L+uT5rz6GLIbCwzbW32sumxcWbk04WQ== dependencies: - "@prisma/debug" "2.28.0" - "@prisma/engine-core" "2.28.0" - "@prisma/engines" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - "@prisma/fetch-engine" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - "@prisma/generator-helper" "2.28.0" - "@prisma/get-platform" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" - "@timsuchanek/copy" "^1.4.5" - archiver "^4.0.0" - arg "^5.0.0" - chalk "4.1.1" + "@prisma/debug" "2.29.1" + "@prisma/get-platform" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@sindresorhus/slugify" "1.1.2" + execa "5.1.1" + global-dirs "3.0.0" + has-yarn "2.1.0" + indent-string "4.0.0" + log-update "4.0.0" + new-github-issue-url "0.2.1" + open "7.4.2" + pkg-up "3.1.0" + prompts "2.4.1" + resolve-pkg "2.0.0" + strip-ansi "6.0.0" + strip-indent "3.0.0" + +"@prisma/sdk@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/sdk/-/sdk-2.29.1.tgz#1619f4f20847caa408c75b9e8175e6a2913c4184" + integrity sha512-vtcF5jdUskjalL5Q9iagbcc+vfwUa+DAQnNdYg0PtmpaS2llWezptvEJd2ihMR7O5m2sAmI87QDiCn9Y5FxNjQ== + dependencies: + "@prisma/debug" "2.29.1" + "@prisma/engine-core" "2.29.1" + "@prisma/engines" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@prisma/fetch-engine" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@prisma/generator-helper" "2.29.1" + "@prisma/get-platform" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@timsuchanek/copy" "1.4.5" + archiver "4.0.2" + arg "5.0.0" + chalk "4.1.2" checkpoint-client "1.1.20" - cli-truncate "^2.1.0" - dotenv "^10.0.0" - execa "^5.0.0" + cli-truncate "2.1.0" + dotenv "10.0.0" + execa "5.1.1" find-up "5.0.0" - global-dirs "^3.0.0" - globby "^11.0.0" - has-yarn "^2.1.0" - is-ci "^3.0.0" - make-dir "^3.0.2" + global-dirs "3.0.0" + globby "11.0.4" + has-yarn "2.1.0" + is-ci "3.0.0" + make-dir "3.1.0" node-fetch "2.6.1" - p-map "^4.0.0" - read-pkg-up "^7.0.1" - resolve "^1.2.0" - rimraf "^3.0.2" - shell-quote "^1.7.2" - string-width "^4.2.0" + p-map "4.0.0" + read-pkg-up "7.0.1" + resolve "1.20.0" + rimraf "3.0.2" + shell-quote "1.7.2" + string-width "4.2.2" strip-ansi "6.0.0" strip-indent "3.0.0" - tar "^6.0.1" - temp-dir "^2.0.0" - temp-write "^4.0.0" - tempy "^1.0.0" - terminal-link "^2.1.1" + tar "6.1.6" + temp-dir "2.0.0" + temp-write "4.0.0" + tempy "1.0.1" + terminal-link "2.1.1" tmp "0.2.1" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": @@ -2350,7 +2382,7 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/slugify@^1.1.0", "@sindresorhus/slugify@^1.1.2": +"@sindresorhus/slugify@1.1.2", "@sindresorhus/slugify@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@sindresorhus/slugify/-/slugify-1.1.2.tgz#c2c0129298b8caace2d9156176fe244d0e83156c" integrity sha512-V9nR/W0Xd9TSGXpZ4iFUcFGhuOJtZX82Fzxj1YISlbSgKvIiNa7eLEZrT0vAraPOt++KHauIVNYgGRgjc13dXA== @@ -2528,7 +2560,7 @@ dependencies: "@babel/runtime" "^7.12.5" -"@timsuchanek/copy@^1.4.5": +"@timsuchanek/copy@1.4.5": version "1.4.5" resolved "https://registry.yarnpkg.com/@timsuchanek/copy/-/copy-1.4.5.tgz#8e9658c056e24e1928a88bed45f9eac6a72b7c40" integrity sha512-N4+2/DvfwzQqHYL/scq07fv8yXbZc6RyUxKJoE8Clm14JpLOf9yNI4VB4D6RsV3h9zgzZ4loJUydHKM7pp3blw== @@ -2665,13 +2697,20 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== -"@types/cross-spawn@^6.0.1": +"@types/cross-spawn@6.0.2": version "6.0.2" resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" integrity sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw== dependencies: "@types/node" "*" +"@types/debug@4.1.7": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + "@types/esrever@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@types/esrever/-/esrever-0.2.0.tgz#96404a2284b2c7527f08a1e957f8a31705f9880f" @@ -2768,9 +2807,9 @@ integrity sha512-Kl5beBoB0OXw7WeFgHHpLEchvC7HyIu3v1AksNNTemAF6jmEmQGqhZQSHcG6BOU/Lq0xsByQNqLzicLPjVkxYQ== "@types/http-assert@*": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b" - integrity sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ== + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.2.tgz#a7fb59a7ca366e141789a084555a633801b9af3b" + integrity sha512-Ddzuzv/bB2prZnJKlS1sEYhaeT50wfJjhcTTTQLjEsEZJlk3XB4Xohieyq+P4VXIzg7lrQ1Spd/PfRnBpQsdqA== "@types/http-errors@*": version "1.8.1" @@ -2801,18 +2840,18 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@*", "@types/jest@^26.0.24": - version "26.0.24" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" - integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== +"@types/jest@*", "@types/jest@^27.0.1": + version "27.0.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.1.tgz#fafcc997da0135865311bb1215ba16dba6bdf4ca" + integrity sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw== dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" + jest-diff "^27.0.0" + pretty-format "^27.0.0" -"@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": - version "7.0.8" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" - integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg== +"@types/json-schema@^7.0.7": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== "@types/keygrip@*": version "1.0.2" @@ -2841,9 +2880,9 @@ "@types/node" "*" "@types/lodash@^4.14.149": - version "4.14.171" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b" - integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg== + version "4.14.172" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.172.tgz#aad774c28e7bfd7a67de25408e03ee5a8c3d028a" + integrity sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw== "@types/long@^4.0.0": version "4.0.1" @@ -2879,6 +2918,11 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + "@types/node-fetch@^2.5.12": version "2.5.12" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" @@ -2898,9 +2942,9 @@ integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== "@types/node@^12.7.1": - version "12.20.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.18.tgz#37a0aab0560d1186da54ee5d62ff6a78cacb8c75" - integrity sha512-YoTiIwdKxM3VLiY2sM05x4iGuTveYiCcDaUVmo1L5ndrXxPGW/NEoZu+pGcBirziomizcZsnsQoemikKcB2fRA== + version "12.20.19" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.19.tgz#538e61fc220f77ae4a4663c3d8c3cb391365c209" + integrity sha512-niAuZrwrjKck4+XhoCw6AAVQBENHftpXw9F4ryk66fTgYaKQ53R4FI7c9vUGGw5vQis1HKBHDR1gcYI/Bq1xvw== "@types/nodemailer@^6.4.4": version "6.4.4" @@ -2980,10 +3024,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17.0.15": - version "17.0.15" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.15.tgz#c7533dc38025677e312606502df7656a6ea626d0" - integrity sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw== +"@types/react@*", "@types/react@^17.0.18": + version "17.0.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.18.tgz#4109cbbd901be9582e5e39e3d77acd7b66bb7fbe" + integrity sha512-YTLgu7oS5zvSqq49X5Iue5oAbVGhgPc5Au29SJC4VeE17V6gASoOxVkUDy9pXFMRFxCWCD9fLeweNFizo3UzOg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -3129,9 +3173,9 @@ "@types/vfile-message" "*" "@types/webpack-sources@*": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.1.1.tgz#6af17e3a3ded71eec2b98008d7c12f498a0a4506" - integrity sha512-MjM1R6iuw8XaVbtkCBz0N349cyqBjJHCbQiOeppe3VBeFvxqs74RKHAVt9LkxTnUWc7YLZOEsUfPUnmK6SBPKQ== + version "3.2.0" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-3.2.0.tgz#16d759ba096c289034b26553d2df1bf45248d38b" + integrity sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg== dependencies: "@types/node" "*" "@types/source-list-map" "*" @@ -3161,13 +3205,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== -"@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^16.0.0": version "16.0.4" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" @@ -3182,86 +3219,86 @@ dependencies: "@types/node" "*" -"@types/zen-observable@^0.8.0": +"@types/zen-observable@0.8.3": version "0.8.3" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== -"@typescript-eslint/eslint-plugin@^4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" - integrity sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA== +"@typescript-eslint/eslint-plugin@^4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d" + integrity sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg== dependencies: - "@typescript-eslint/experimental-utils" "4.29.0" - "@typescript-eslint/scope-manager" "4.29.0" + "@typescript-eslint/experimental-utils" "4.29.2" + "@typescript-eslint/scope-manager" "4.29.2" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.29.0", "@typescript-eslint/experimental-utils@^4.0.1", "@typescript-eslint/experimental-utils@^4.2.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz#19b1417602d0e1ef325b3312ee95f61220542df5" - integrity sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w== +"@typescript-eslint/experimental-utils@4.29.2", "@typescript-eslint/experimental-utils@^4.0.1", "@typescript-eslint/experimental-utils@^4.2.0": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz#5f67fb5c5757ef2cb3be64817468ba35c9d4e3b7" + integrity sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.0" - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/typescript-estree" "4.29.0" + "@typescript-eslint/scope-manager" "4.29.2" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/typescript-estree" "4.29.2" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/parser@^4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.0.tgz#e5367ca3c63636bb5d8e0748fcbab7a4f4a04289" - integrity sha512-+92YRNHFdXgq+GhWQPT2bmjX09X7EH36JfgN2/4wmhtwV/HPxozpCNst8jrWcngLtEVd/4zAwA6BKojAlf+YqA== +"@typescript-eslint/parser@^4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.2.tgz#1c7744f4c27aeb74610c955d3dce9250e95c370a" + integrity sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g== dependencies: - "@typescript-eslint/scope-manager" "4.29.0" - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/typescript-estree" "4.29.0" + "@typescript-eslint/scope-manager" "4.29.2" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/typescript-estree" "4.29.2" debug "^4.3.1" -"@typescript-eslint/scope-manager@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz#cf5474f87321bedf416ef65839b693bddd838599" - integrity sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w== +"@typescript-eslint/scope-manager@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz#442b0f029d981fa402942715b1718ac7fcd5aa1b" + integrity sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA== dependencies: - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/visitor-keys" "4.29.0" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/visitor-keys" "4.29.2" -"@typescript-eslint/types@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" - integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== +"@typescript-eslint/types@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.2.tgz#fc0489c6b89773f99109fb0aa0aaddff21f52fcd" + integrity sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ== -"@typescript-eslint/typescript-estree@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz#af7ab547757b86c91bfdbc54ff86845410856256" - integrity sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ== +"@typescript-eslint/typescript-estree@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz#a0ea8b98b274adbb2577100ba545ddf8bf7dc219" + integrity sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg== dependencies: - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/visitor-keys" "4.29.0" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/visitor-keys" "4.29.2" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz#1ff60f240def4d85ea68d4fd2e4e9759b7850c04" - integrity sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q== +"@typescript-eslint/visitor-keys@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz#d2da7341f3519486f50655159f4e5ecdcb2cd1df" + integrity sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag== dependencies: - "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/types" "4.29.2" eslint-visitor-keys "^2.0.0" "@wry/context@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.0.tgz#f903eceb89d238ef7e8168ed30f4511f92d83e06" - integrity sha512-sAgendOXR8dM7stJw3FusRxFHF/ZinU0lffsA2YTyyIOfic86JX02qlPqPVqJNZJPAxFt+2EE8bvq6ZlS0Kf+Q== + version "0.6.1" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" + integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw== dependencies: - tslib "^2.1.0" + tslib "^2.3.0" "@wry/equality@^0.1.2": version "0.1.11" @@ -3271,18 +3308,18 @@ tslib "^1.9.3" "@wry/equality@^0.5.0": - version "0.5.1" - resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.1.tgz#b22e4e1674d7bf1439f8ccdccfd6a785f6de68b0" - integrity sha512-FZKbdpbcVcbDxQrKcaBClNsQaMg9nof1RKM7mReJe5DKUzM5u8S7T+PqwNqvib5O2j2xxF1R4p5O3+b6baTrbw== + version "0.5.2" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" + integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA== dependencies: - tslib "^2.1.0" + tslib "^2.3.0" "@wry/trie@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.0.tgz#3245e74988c4e3033299e479a1bf004430752463" - integrity sha512-Yw1akIogPhAT6XPYsRHlZZIS0tIGmAl9EYXHi2scf7LPKKqdqmow/Hu4kEqP2cJR3EjaU/9L0ZlAjFf3hFxmug== + version "0.3.1" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.1.tgz#2279b790f15032f8bcea7fc944d27988e5b3b139" + integrity sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw== dependencies: - tslib "^2.1.0" + tslib "^2.3.0" abab@^2.0.3, abab@^2.0.5: version "2.0.5" @@ -3348,12 +3385,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -3663,7 +3695,7 @@ archiver-utils@^2.1.0: normalize-path "^3.0.0" readable-stream "^2.0.0" -archiver@^4.0.0: +archiver@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/archiver/-/archiver-4.0.2.tgz#43c72865eadb4ddaaa2fb74852527b6a450d927c" integrity sha512-B9IZjlGwaxF33UN4oPbfBkyA4V1SxNLeIhR1qY8sRXSsbdUkEHrrOvwlYFPx+8uQeCe9M+FG6KgO+imDmQ79CQ== @@ -3681,7 +3713,7 @@ arg@4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== -arg@^5.0.0: +arg@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.0.tgz#a20e2bb5710e82950a516b3f933fee5ed478be90" integrity sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ== @@ -3856,9 +3888,9 @@ async-retry@^1.2.1: retry "0.12.0" async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + version "3.2.1" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8" + integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg== asynckit@^0.4.0: version "0.4.0" @@ -3875,7 +3907,7 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -available-typed-arrays@^1.0.2: +available-typed-arrays@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz#9e0ae84ecff20caae6a94a1c3bc39b955649b7a9" integrity sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA== @@ -4277,7 +4309,7 @@ browserify-zlib@0.2.0, browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.16.6, browserslist@^4.16.6: +browserslist@4.16.6: version "4.16.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== @@ -4288,6 +4320,17 @@ browserslist@4.16.6, browserslist@^4.16.6: escalade "^3.1.1" node-releases "^1.1.71" +browserslist@^4.16.6, browserslist@^4.16.7: + version "4.16.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.7.tgz#108b0d1ef33c4af1b587c54f390e7041178e4335" + integrity sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA== + dependencies: + caniuse-lite "^1.0.30001248" + colorette "^1.2.2" + electron-to-chromium "^1.3.793" + escalade "^3.1.1" + node-releases "^1.1.73" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -4456,10 +4499,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228: - version "1.0.30001248" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz#26ab45e340f155ea5da2920dadb76a533cb8ebce" - integrity sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw== +caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001248: + version "1.0.30001251" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz#6853a606ec50893115db660f82c094d18f096d85" + integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A== caseless@~0.12.0: version "0.12.0" @@ -4499,10 +4542,10 @@ chalk@4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" @@ -4526,14 +4569,6 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -4710,6 +4745,14 @@ cli-table3@~0.6.0: optionalDependencies: colors "^1.1.2" +cli-truncate@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + cli-truncate@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" @@ -4718,14 +4761,6 @@ cli-truncate@^0.2.1: slice-ansi "0.0.4" string-width "^1.0.1" -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - clipboard-copy@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clipboard-copy/-/clipboard-copy-4.0.1.tgz#326ef9726d4ffe72d9a82a7bbe19379de692017d" @@ -4838,9 +4873,9 @@ color-name@~1.1.4: integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af" + integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w== colors@^1.1.2: version "1.4.0" @@ -4993,17 +5028,17 @@ copy-to-clipboard@^3.3.1: toggle-selection "^1.0.6" core-js-compat@^3.14.0, core-js-compat@^3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.0.tgz#fced4a0a534e7e02f7e084bff66c701f8281805f" - integrity sha512-5D9sPHCdewoUK7pSUPfTF7ZhLh8k9/CoJXWUEo+F1dZT5Z1DVgcuRqUKhjeKW+YLb8f21rTFgWwQJiNw1hoZ5Q== + version "3.16.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.1.tgz#c44b7caa2dcb94b673a98f27eee1c8312f55bc2d" + integrity sha512-NHXQXvRbd4nxp9TEmooTJLUf94ySUG6+DSsscBpTftN1lQLQ4LjnWvc7AoIo4UjDsFF3hB8Uh5LLCRRdaiT5MQ== dependencies: - browserslist "^4.16.6" + browserslist "^4.16.7" semver "7.0.0" core-js-pure@^3.10.2, core-js-pure@^3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.0.tgz#218e07add3f1844e53fab195c47871fc5ba18de8" - integrity sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ== + version "3.16.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.1.tgz#b997df2669c957a5b29f06e95813a171f993592e" + integrity sha512-TyofCdMzx0KMhi84mVRS8rL1XsRk2SPUNz2azmth53iRN0/08Uim9fdhQTaZTG1LqaXHYVci4RDHka6WrXfnvg== core-js@3.6.5: version "3.6.5" @@ -5011,9 +5046,9 @@ core-js@3.6.5: integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== core-js@^3.1.3: - version "3.16.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.0.tgz#1d46fb33720bc1fa7f90d20431f36a5540858986" - integrity sha512-5+5VxRFmSf97nM8Jr2wzOwLqRo6zphH2aX+7KsAUONObyzakDNq2G/bgbhinxB4PoV9L3aXQYhiDKyIKWd2c8g== + version "3.16.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.1.tgz#f4485ce5c9f3c6a7cb18fa80488e08d362097249" + integrity sha512-AAkP8i35EbefU+JddyWi12AWE9f2N/qr/pwnDtWz4nyUIBGMJPX99ANFFRSw6FefM374lDujdtLDyhN2A/btHw== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -5110,6 +5145,15 @@ cross-fetch@^3.1.4: dependencies: node-fetch "2.6.1" +cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -5119,15 +5163,6 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - crypto-browserify@3.12.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -5217,6 +5252,13 @@ cssnano-preset-simple@^2.0.0: dependencies: caniuse-lite "^1.0.30001202" +cssnano-preset-simple@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssnano-preset-simple/-/cssnano-preset-simple-3.0.0.tgz#e95d0012699ca2c741306e9a3b8eeb495a348dbe" + integrity sha512-vxQPeoMRqUT3c/9f0vWeVa2nKQIHFpogtoBvFdW4GQ3IvEJ6uauCP6p3Y5zQDLFcI7/+40FTgX12o7XUL0Ko+w== + dependencies: + caniuse-lite "^1.0.30001202" + cssnano-simple@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/cssnano-simple/-/cssnano-simple-2.0.0.tgz#930d9dcd8ba105c5a62ce719cb00854da58b5c05" @@ -5224,6 +5266,13 @@ cssnano-simple@2.0.0: dependencies: cssnano-preset-simple "^2.0.0" +cssnano-simple@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssnano-simple/-/cssnano-simple-3.0.0.tgz#a4b8ccdef4c7084af97e19bc5b93b4ecf211e90f" + integrity sha512-oU3ueli5Dtwgh0DyeohcIEE00QVfbPR3HzyXdAl89SfnQG3y0/qcpfLVW+jPIh3/rgMZGwuW96rejZGaYE9eUg== + dependencies: + cssnano-preset-simple "^3.0.0" + csso@^4.0.2: version "4.2.0" resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" @@ -5573,11 +5622,6 @@ dicer@0.3.0: dependencies: streamsearch "0.1.2" -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - diff-sequences@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" @@ -5626,9 +5670,9 @@ doctrine@^3.0.0: esutils "^2.0.2" dom-accessibility-api@^0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9" - integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw== + version "0.5.7" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.7.tgz#8c2aa6325968f2933160a0b7dbb380893ddf3e7d" + integrity sha512-ml3lJIq9YjUfM9TUnEPvEYWFSwivwIGBPKpewX7tii7fwCazA8yCioGdqQcNsItPpfFvSJ3VIdMQPj60LJhcQA== dom-helpers@^5.0.1: version "5.2.1" @@ -5688,7 +5732,7 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" -dotenv@^10.0.0: +dotenv@10.0.0, dotenv@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== @@ -5733,10 +5777,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.723: - version "1.3.793" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.793.tgz#c10dff5f3126238004de344db458f1da3641d554" - integrity sha512-l9NrGV6Mr4ov5mayYPvIWcwklNw5ROmy6rllzz9dCACw9nKE5y+s5uQk+CBJMetxrWZ6QJFsvEfG6WDcH2IGUg== +electron-to-chromium@^1.3.723, electron-to-chromium@^1.3.793: + version "1.3.806" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.806.tgz#21502100f11aead6c501d1cd7f2504f16c936642" + integrity sha512-AH/otJLAAecgyrYp0XK1DPiGVWcOgwPeJBOLeuFQ5l//vhQhwC9u6d+GijClqJAmsHG4XDue81ndSQPohUu0xA== elegant-spinner@^1.0.1: version "1.0.1" @@ -5824,7 +5868,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: +es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2, es-abstract@^1.18.5: version "1.18.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19" integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA== @@ -5898,18 +5942,18 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-import-resolver-node@^0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== +eslint-import-resolver-node@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.5.tgz#939bbb0f74e179e757ca87f7a4a890dabed18ac4" + integrity sha512-XMoPKjSpXbkeJ7ZZ9icLnJMTY5Mc1kZbCakHquaFsXPpyWOwK0TK6CODO+0ca54UoM9LKOxyUNnoVZRl8TeaAg== dependencies: - debug "^2.6.9" - resolve "^1.13.1" + debug "^3.2.7" + resolve "^1.20.0" -eslint-module-utils@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233" - integrity sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A== +eslint-module-utils@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534" + integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q== dependencies: debug "^3.2.7" pkg-dir "^2.0.0" @@ -5921,17 +5965,17 @@ eslint-plugin-cypress@^2.11.3: dependencies: globals "^11.12.0" -eslint-plugin-import@^2.23.3: - version "2.23.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.3.tgz#8a1b073289fff03c4af0f04b6df956b7d463e191" - integrity sha512-wDxdYbSB55F7T5CC7ucDjY641VvKmlRwT0Vxh7PkY1mI4rclVRFWYfsrjDgZvwYYDZ5ee0ZtfFKXowWjqvEoRQ== +eslint-plugin-import@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.0.tgz#697ffd263e24da5e84e03b282f5fb62251777177" + integrity sha512-Kc6xqT9hiYi2cgybOc0I2vC9OgAYga5o/rAFinam/yF/t5uBqxQbauNPMC6fgb640T/89P0gFoO27FOilJ/Cqg== dependencies: array-includes "^3.1.3" array.prototype.flat "^1.2.4" debug "^2.6.9" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.1" + eslint-import-resolver-node "^0.3.5" + eslint-module-utils "^2.6.2" find-up "^2.0.0" has "^1.0.3" is-core-module "^2.4.0" @@ -6480,14 +6524,6 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-loader@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - file-type@^10.10.0: version "10.11.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-10.11.0.tgz#2961d09e4675b9fb9a3ee6b69e9cd23f43fd1890" @@ -6629,12 +6665,12 @@ focus-lock@^0.9.1: dependencies: tslib "^2.0.3" -focus-trap@^6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-6.6.0.tgz#7fb37679926ec1bd762d0748b056c68a64a9e8cf" - integrity sha512-2hWVR3XbBejn5v8wDW9DFzLWXcxMNaSJ/CtE3E+FJjjBCLwIYbZJwjUi2RDBfQPM58gHEt5hck0jrJgHR9/s+A== +focus-trap@^6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-6.6.1.tgz#761ce2c82ddd72beeb049e968bc8414e25b704aa" + integrity sha512-x9BWuAeF5UrfWuYKJ3jYrjcVYSYptS9CqtxH5IH7lPlZrMsaugKeAa0HtoZSBZe5DmeTMx2m0qY464ZMzqarzw== dependencies: - tabbable "^5.2.0" + tabbable "^5.2.1" follow-redirects@^1.10.0: version "1.14.1" @@ -6864,6 +6900,11 @@ get-stdin@^6.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== +get-stream@6.0.1, get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -6883,11 +6924,6 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -6976,6 +7012,13 @@ glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +global-dirs@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== + dependencies: + ini "2.0.0" + global-dirs@^2.0.1: version "2.1.0" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" @@ -6983,26 +7026,19 @@ global-dirs@^2.0.1: dependencies: ini "1.3.7" -global-dirs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" - integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== - dependencies: - ini "2.0.0" - globals@^11.1.0, globals@^11.12.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.6.0, globals@^13.9.0: - version "13.10.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.10.0.tgz#60ba56c3ac2ca845cfbf4faeca727ad9dd204676" - integrity sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g== + version "13.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" + integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== dependencies: type-fest "^0.20.2" -globby@^11.0.0, globby@^11.0.1, globby@^11.0.3, globby@^11.0.4: +globby@11.0.4, globby@^11.0.0, globby@^11.0.1, globby@^11.0.3, globby@^11.0.4: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== @@ -7058,9 +7094,9 @@ got@^9.6.0: url-parse-lax "^3.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.5, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== grapheme-splitter@^1.0.4: version "1.0.4" @@ -7083,7 +7119,7 @@ graphql-subscriptions@^1.0.0: dependencies: iterall "^1.3.0" -graphql-tag@^2.11.0, graphql-tag@^2.12.0, graphql-tag@^2.12.5: +graphql-tag@^2.11.0, graphql-tag@^2.12.3, graphql-tag@^2.12.5: version "2.12.5" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f" integrity sha512-5xNhP4063d16Pz3HBtKprutsPrmHZi5IdUGOWRxA2B6VF7BIRGOHZ5WQvDmJXZuPcBg7rYwaFxvQYjqkSdR3TQ== @@ -7167,6 +7203,13 @@ has-symbols@^1.0.1, has-symbols@^1.0.2: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -7198,7 +7241,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has-yarn@^2.1.0: +has-yarn@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== @@ -7468,7 +7511,7 @@ ignore@^5.1.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -image-size@^1.0.0: +image-size@1.0.0, image-size@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.0.tgz#58b31fe4743b1cec0a0ac26f5c914d3c5b2f0750" integrity sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw== @@ -7508,16 +7551,16 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indent-string@4.0.0, indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + indent-string@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - inflection@^1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.1.tgz#c5cadd80888a90cf84c2e96e340d7edc85d5f0cb" @@ -7637,11 +7680,12 @@ is-alphanumerical@^1.0.0: is-decimal "^1.0.0" is-arguments@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" - integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" @@ -7649,9 +7693,11 @@ is-arrayish@^0.2.1: integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-bigint@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" - integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" is-binary-path@^1.0.0: version "1.0.1" @@ -7668,11 +7714,12 @@ is-binary-path@~2.1.0: binary-extensions "^2.0.0" is-boolean-object@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" - integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: call-bind "^1.0.2" + has-tostringtag "^1.0.0" is-buffer@^1.1.5: version "1.1.6" @@ -7685,9 +7732,16 @@ is-buffer@^2.0.0: integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" - integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-ci@3.0.0, is-ci@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994" + integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ== + dependencies: + ci-info "^3.1.1" is-ci@^2.0.0: version "2.0.0" @@ -7696,13 +7750,6 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-ci@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994" - integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ== - dependencies: - ci-info "^3.1.1" - is-core-module@^2.2.0, is-core-module@^2.4.0: version "2.5.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" @@ -7725,9 +7772,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" - integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-decimal@^1.0.0: version "1.0.4" @@ -7812,9 +7861,11 @@ is-generator-fn@^2.0.0: integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== is-generator-function@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.9.tgz#e5f82c2323673e7fcad3d12858c83c4039f6399c" - integrity sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A== + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" is-glob@^2.0.0: version "2.0.1" @@ -7884,9 +7935,11 @@ is-negative-zero@^2.0.1: integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== is-number-object@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" - integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" is-number@^3.0.0: version "3.0.0" @@ -7967,12 +8020,12 @@ is-reference@^1.1.4, is-reference@^1.2.1: "@types/estree" "*" is-regex@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" - integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: call-bind "^1.0.2" - has-symbols "^1.0.2" + has-tostringtag "^1.0.0" is-stream@1.1.0, is-stream@^1.1.0: version "1.1.0" @@ -7985,9 +8038,11 @@ is-stream@^2.0.0: integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== is-string@^1.0.5, is-string@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" - integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" is-subdir@^1.1.1: version "1.2.0" @@ -8003,16 +8058,16 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" - integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== +is-typed-array@^1.1.3, is-typed-array@^1.1.6: + version "1.1.7" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.7.tgz#881ddc660b13cb8423b2090fa88c0fe37a83eb2f" + integrity sha512-VxlpTBGknhQ3o7YiVjIhdLU6+oD8dPz/79vvvH4F+S/c8608UCVa9fgDpa1kZgFoUST2DCgacc70UszKgzKuvA== dependencies: - available-typed-arrays "^1.0.2" + available-typed-arrays "^1.0.4" call-bind "^1.0.2" - es-abstract "^1.18.0-next.2" + es-abstract "^1.18.5" foreach "^2.0.5" - has-symbols "^1.0.1" + has-tostringtag "^1.0.0" is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" @@ -8208,17 +8263,7 @@ jest-config@^27.0.6: micromatch "^4.0.4" pretty-format "^27.0.6" -jest-diff@^26.0.0: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-diff@^27.0.6: +jest-diff@^27.0.0, jest-diff@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.0.6.tgz#4a7a19ee6f04ad70e0e3388f35829394a44c7b5e" integrity sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg== @@ -8271,11 +8316,6 @@ jest-environment-node@^27.0.6: jest-mock "^27.0.6" jest-util "^27.0.6" -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - jest-get-type@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" @@ -9015,16 +9055,7 @@ log-symbols@^4.0.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log-update@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" - integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= - dependencies: - ansi-escapes "^3.0.0" - cli-cursor "^2.0.0" - wrap-ansi "^3.0.1" - -log-update@^4.0.0: +log-update@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== @@ -9034,6 +9065,15 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +log-update@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" + integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= + dependencies: + ansi-escapes "^3.0.0" + cli-cursor "^2.0.0" + wrap-ansi "^3.0.1" + loglevel@^1.6.7: version "1.7.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" @@ -9626,7 +9666,7 @@ mime-db@1.49.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.32" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== @@ -9776,14 +9816,14 @@ multipipe@^1.0.2: object-assign "^4.1.0" nan@^2.12.1: - version "2.14.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" - integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== -nanoid@^3.1.22: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== +nanoid@^3.1.22, nanoid@^3.1.23: + version "3.1.25" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== nanomatch@^1.2.9: version "1.2.13" @@ -9819,7 +9859,7 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -new-github-issue-url@^0.2.1: +new-github-issue-url@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz#e17be1f665a92de465926603e44b9f8685630c1d" integrity sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA== @@ -9829,18 +9869,10 @@ next-compose-plugins@^2.2.1: resolved "https://registry.yarnpkg.com/next-compose-plugins/-/next-compose-plugins-2.2.1.tgz#020fc53f275a7e719d62521bef4300fbb6fde5ab" integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg== -next-images@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/next-images/-/next-images-1.8.1.tgz#adea0c46a2e837cb49b6f95b478500a7ed4eea4f" - integrity sha512-/DoXucQKWkEBT2rCQKtm9bb+KTAnd1vVTLO12lX4oxdiBQa2uqn5vhcMPwKsdJlxNBzwg6EVnddFs3aqcwiiGA== - dependencies: - file-loader "^6.2.0" - url-loader "^4.1.0" - -next-sitemap@^1.6.140: - version "1.6.140" - resolved "https://registry.yarnpkg.com/next-sitemap/-/next-sitemap-1.6.140.tgz#b391633596f4845ec9ceb54a51da8c1f6f97ae43" - integrity sha512-VTOQMae/nDLBRGBHnkmGoIsArymlOpJWkZUDvPapktF4QX2U7yvwHIHe7V7amqV2gE2xiDYgd0ayXOBBGuFHog== +next-sitemap@^1.6.157: + version "1.6.157" + resolved "https://registry.yarnpkg.com/next-sitemap/-/next-sitemap-1.6.157.tgz#9e894188217ec94a00d4e10ddebb92393a3ea14a" + integrity sha512-5aIGplbGj0vRsetVla1ZW+0CaRtFnDY9ffW8qqii/nAfOyFuBgaHgKS92TsuBPNzz7O0/7vz4x8jZXEoR9tg2w== dependencies: "@corex/deepmerge" "^2.6.20" matcher "^4.0.0" @@ -9902,6 +9934,62 @@ next@^10.2.3: vm-browserify "1.1.2" watchpack "2.1.1" +"next@npm:next@^11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/next/-/next-11.1.0.tgz#767d4c4fa0b9b0c768cdbd6c9f03dd86b5d701c0" + integrity sha512-GHBk/c7Wyr6YbFRFZF37I0X7HKzkHHI8pur/loyXo5AIE8wdkbGPGO0ds3vNAO6f8AxZAKGCRYtAzoGlVLoifA== + dependencies: + "@babel/runtime" "7.12.5" + "@hapi/accept" "5.0.2" + "@next/env" "11.1.0" + "@next/polyfill-module" "11.1.0" + "@next/react-dev-overlay" "11.1.0" + "@next/react-refresh-utils" "11.1.0" + "@node-rs/helper" "1.2.1" + assert "2.0.0" + ast-types "0.13.2" + browserify-zlib "0.2.0" + browserslist "4.16.6" + buffer "5.6.0" + caniuse-lite "^1.0.30001228" + chalk "2.4.2" + chokidar "3.5.1" + constants-browserify "1.0.0" + crypto-browserify "3.12.0" + cssnano-simple "3.0.0" + domain-browser "4.19.0" + encoding "0.1.13" + etag "1.8.1" + find-cache-dir "3.3.1" + get-orientation "1.1.2" + https-browserify "1.0.0" + image-size "1.0.0" + jest-worker "27.0.0-next.5" + native-url "0.3.4" + node-fetch "2.6.1" + node-html-parser "1.4.9" + node-libs-browser "^2.2.1" + os-browserify "0.3.0" + p-limit "3.1.0" + path-browserify "1.0.1" + pnp-webpack-plugin "1.6.4" + postcss "8.2.15" + process "0.11.10" + querystring-es3 "0.2.1" + raw-body "2.4.1" + react-is "17.0.2" + react-refresh "0.8.3" + stream-browserify "3.0.0" + stream-http "3.1.1" + string_decoder "1.3.0" + styled-jsx "4.0.0" + timers-browserify "2.0.12" + tty-browserify "0.0.1" + use-subscription "1.5.1" + util "0.12.3" + vm-browserify "1.1.2" + watchpack "2.1.1" + node-fetch@2.6.1, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -9953,10 +10041,10 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-releases@^1.1.71: - version "1.1.73" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" - integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== +node-releases@^1.1.71, node-releases@^1.1.73: + version "1.1.74" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.74.tgz#e5866488080ebaa70a93b91144ccde06f3c3463e" + integrity sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw== nodemailer@^6.6.3: version "6.6.3" @@ -10208,7 +10296,7 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -open@^7.0.3: +open@7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -10216,7 +10304,7 @@ open@^7.0.3: is-docker "^2.0.0" is-wsl "^2.1.1" -optimism@^0.16.0: +optimism@^0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== @@ -10349,19 +10437,19 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-map@^4.0.0: +p-map@4.0.0, p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" -p-retry@^4.2.0: +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-retry@4.6.1, p-retry@^4.2.0: version "4.6.1" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.1.tgz#8fcddd5cdf7a67a0911a9cf2ef0e5df7f602316c" integrity sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA== @@ -10623,6 +10711,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-up@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" @@ -10630,22 +10725,15 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - platform@1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== -playwright@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.13.1.tgz#53c49244ffa7fc2d5d8bf7ce87739393206eda5e" - integrity sha512-pGbILcUV1+Yx0fcRJZBEIsqTDjQSwGYkJ4tVUQUtuAyMuHg5B++Nasl+pIeIJRMqKSWTyvZfPxJuPIGsLJgiFg== +playwright@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.14.0.tgz#18301b11f5278a446d36b5cf96f67db36ce2cd20" + integrity sha512-aR5oZ1iVsjQkGfYCjgYAmyMAVu0MQ0i8MgdnfdqDu9EVLfbnpuuFmTv/Rb7/Yjno1kOrDUP9+RyNC+zfG3wozA== dependencies: commander "^6.1.0" debug "^4.1.1" @@ -10693,6 +10781,15 @@ postcss@8.2.13: nanoid "^3.1.22" source-map "^0.6.1" +postcss@8.2.15: + version "8.2.15" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65" + integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.23" + source-map "^0.6.1" + preferred-pm@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/preferred-pm/-/preferred-pm-3.0.3.tgz#1b6338000371e3edbce52ef2e4f65eb2e73586d6" @@ -10733,17 +10830,7 @@ pretty-bytes@^5.4.1: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== -pretty-format@^26.0.0, pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-format@^27.0.2, pretty-format@^27.0.6: +pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.6.tgz#ab770c47b2c6f893a21aefc57b75da63ef49a11f" integrity sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ== @@ -10763,12 +10850,12 @@ prism-react-renderer@^1.2.1: resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz#392460acf63540960e5e3caa699d851264e99b89" integrity sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg== -prisma@2.28.0: - version "2.28.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.28.0.tgz#33adb56e336d4c4569ec2f49df9b606771df15d0" - integrity sha512-f83KPLy3xk07KMY4e5otNwP2I+GsdftjOfu3e8snXylnyAC1oEpRZNe7rmONr0vAI+Qgz3LFRArhWUE/dFjKIA== +prisma@2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.29.1.tgz#7845f55c7f09955b01f973c6a4b1f330cb212e7d" + integrity sha512-fRGh90+z0m3Jw3D6KBE6wyVCRR0w6M6QD93jh+em8IOQycmC48zB8hho8zeri3J9//C0k8fkDeQrRLJUosXROw== dependencies: - "@prisma/engines" "2.28.0-17.89facabd0366f63911d089156a7a70125bfbcd27" + "@prisma/engines" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" process-nextick-args@~2.0.0: version "2.0.1" @@ -10785,7 +10872,7 @@ progress@^2.0.0, progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prompts@^2.0.1, prompts@^2.3.2, prompts@^2.4.1: +prompts@2.4.1, prompts@^2.0.1, prompts@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== @@ -11069,7 +11156,7 @@ react-is@16.13.1, react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.1: +react-is@17.0.2, react-is@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== @@ -11154,15 +11241,7 @@ react@^17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg-up@^7.0.1: +read-pkg-up@7.0.1, read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== @@ -11171,6 +11250,14 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -11570,7 +11657,7 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-pkg@^2.0.0: +resolve-pkg@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41" integrity sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ== @@ -11582,7 +11669,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.2.0, resolve@^1.20.0: +resolve@1.20.0, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -11649,7 +11736,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -11665,9 +11752,9 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: inherits "^2.0.1" rollup@^2.32.0: - version "2.55.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.55.1.tgz#66a444648e2fb603d8e329e77a61c608a6510fda" - integrity sha512-1P9w5fpb6b4qroePh8vHKGIvPNxwoCQhjJpIqfZGHLKpZ0xcU2/XBmFxFbc9697/6bmHpmFTLk5R1dAQhFSo0g== + version "2.56.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.2.tgz#a045ff3f6af53ee009b5f5016ca3da0329e5470f" + integrity sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ== optionalDependencies: fsevents "~2.3.2" @@ -11734,15 +11821,6 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -schema-utils@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - scroll-into-view-if-needed@^2.2.20, scroll-into-view-if-needed@^2.2.28: version "2.2.28" resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz#5a15b2f58a52642c88c8eca584644e01703d645a" @@ -11876,7 +11954,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@1.7.2, shell-quote@^1.7.2: +shell-quote@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== @@ -12117,9 +12195,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" - integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== + version "3.0.10" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b" + integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -12286,6 +12364,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +string-width@4.2.2, string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -12303,15 +12390,6 @@ string-width@^2.0.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - string.prototype.matchall@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" @@ -12450,10 +12528,10 @@ strip-outer@^1.0.1: dependencies: escape-string-regexp "^1.0.2" -stripe@^8.167.0: - version "8.167.0" - resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.167.0.tgz#a7d7bd3828fa34210f9101b061b10f56b3a45b18" - integrity sha512-iWrof4zc/TRjzKr181Tj5Tz/RaxpNQjqkkVjjfqmzXuSY1tNV4HTbS26ucsBNkw2MJZr/q1Hx8gWDRdhZ8FG2g== +stripe@^8.169.0: + version "8.169.0" + resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.169.0.tgz#5970cc055872fccbc49713f6428a682ece7f3e76" + integrity sha512-h4JVMGnhYwkEu8dFHX0MewtTFEWcjJQ2zTiFcvhW5toa/2JcEeObfwH27Z29A6t/6s2vnXrXxEnuyL7gBBAXqA== dependencies: "@types/node" ">=8.1.0" qs "^6.6.0" @@ -12479,6 +12557,20 @@ styled-jsx@3.3.2: stylis "3.5.4" stylis-rule-sheet "0.0.10" +styled-jsx@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-4.0.0.tgz#f7b90e7889d0a4f4635f8d1ae9ac32f3acaedc57" + integrity sha512-2USeoWMoJ/Lx5s2y1PxuvLy/cz2Yrr8cTySV3ILHU1Vmaw1bnV7suKdblLPjnyhMD+qzN7B1SWyh4UZTARn/WA== + dependencies: + "@babel/plugin-syntax-jsx" "7.14.5" + "@babel/types" "7.15.0" + convert-source-map "1.7.0" + loader-utils "1.2.3" + source-map "0.7.3" + string-hash "1.1.3" + stylis "3.5.4" + stylis-rule-sheet "0.0.10" + stylis-rule-sheet@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" @@ -12522,10 +12614,10 @@ superagent@^6.1.0: readable-stream "^3.6.0" semver "^7.3.2" -supertest@^6.1.4: - version "6.1.4" - resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.1.4.tgz#ea8953343e0ca316e80e975b39340934f754eb06" - integrity sha512-giC9Zm+Bf1CZP09ciPdUyl+XlMAu6rbch79KYiYKOGcbK2R1wH8h+APul1i/3wN6RF1XfWOIF+8X1ga+7SBrug== +supertest@^6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.1.5.tgz#b011c8465281b30c64e9d4be4cb3808b91cd1ec0" + integrity sha512-Is3pFB2TxSFPohDS2tIM8h2JOMvUQwbJ9TvTfsWAm89ZZv1CF4VTLAsQz+5+5S1wOgaMqFqSpFriU15L3e2AXQ== dependencies: methods "^1.1.2" superagent "^6.1.0" @@ -12603,10 +12695,10 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -tabbable@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.2.0.tgz#4fba60991d8bb89d06e5d9455c92b453acf88fb2" - integrity sha512-0uyt8wbP0P3T4rrsfYg/5Rg3cIJ8Shl1RJ54QMqYxm1TLdWqJD1u6+RQjr2Lor3wmfT7JRHkirIwy99ydBsyPg== +tabbable@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.2.1.tgz#e3fda7367ddbb172dcda9f871c0fdb36d1c4cd9c" + integrity sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ== table@^6.0.9: version "6.7.1" @@ -12631,10 +12723,10 @@ tar-stream@^2.1.2: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^6.0.1: - version "6.1.3" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.3.tgz#e44b97ee7d6cc7a4c574e8b01174614538291825" - integrity sha512-3rUqwucgVZXTeyJyL2jqtUau8/8r54SioM1xj3AmTX3HnWQdj2AydfJ2qYYayPyIIznSplcvU9mhBb7dR2XF3w== +tar@6.1.6: + version "6.1.6" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.6.tgz#c23d797b0a1efe5d479b1490805c5443f3560c5d" + integrity sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -12643,17 +12735,17 @@ tar@^6.0.1: mkdirp "^1.0.3" yallist "^4.0.0" +temp-dir@2.0.0, temp-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" + integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= -temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - -temp-write@^4.0.0: +temp-write@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== @@ -12664,15 +12756,7 @@ temp-write@^4.0.0: temp-dir "^1.0.0" uuid "^3.3.2" -tempy@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.2.1.tgz#9038e4dbd1c201b74472214179bc2c6f7776e54c" - integrity sha512-LB83o9bfZGrntdqPuRdanIVCPReam9SOZKW0fOy5I9X3A854GGWi0tjCqoXEk84XIEYBc/x9Hq3EFop/H5wJaw== - dependencies: - temp-dir "^1.0.0" - unique-string "^1.0.0" - -tempy@^1.0.0: +tempy@1.0.1, tempy@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.1.tgz#30fe901fd869cfb36ee2bd999805aa72fbb035de" integrity sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w== @@ -12683,6 +12767,14 @@ tempy@^1.0.0: type-fest "^0.16.0" unique-string "^2.0.0" +tempy@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.2.1.tgz#9038e4dbd1c201b74472214179bc2c6f7776e54c" + integrity sha512-LB83o9bfZGrntdqPuRdanIVCPReam9SOZKW0fOy5I9X3A854GGWi0tjCqoXEk84XIEYBc/x9Hq3EFop/H5wJaw== + dependencies: + temp-dir "^1.0.0" + unique-string "^1.0.0" + term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -12703,7 +12795,7 @@ terminal-link-cli@^3.0.0: meow "^9.0.0" terminal-link "^3.0.0" -terminal-link@^2.0.0, terminal-link@^2.1.1: +terminal-link@2.1.1, terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== @@ -12970,10 +13062,10 @@ ts-invariant@^0.4.0: dependencies: tslib "^1.9.3" -ts-invariant@^0.8.0: - version "0.8.2" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.8.2.tgz#62af654ebfb8b1eeb55bc9adc2f40c6b93b0ff7e" - integrity sha512-VI1ZSMW8soizP5dU8DsMbj/TncHf7bIUqavuE7FTeYeQat454HHurJ8wbfCnVWcDOMkyiBUWOW2ytew3xUxlRw== +ts-invariant@^0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.1.tgz#87dfde9894a4ce3c7711b02b1b449e7fd7384b13" + integrity sha512-hSeYibh29ULlHkuEfukcoiyTct+s2RzczMLTv4x3NWC/YrBy7x7ps5eYq/b4Y3Sb9/uAlf54+/5CAEMVxPhuQw== dependencies: tslib "^2.1.0" @@ -12996,10 +13088,10 @@ tslib@^1.0.0, tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" - integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@~2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tslib@~2.1.0: version "2.1.0" @@ -13107,9 +13199,9 @@ type-fest@^0.8.0, type-fest@^0.8.1: integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-fest@^1.0.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.3.0.tgz#6be848243853df1173fa95530112e1358ab0810b" - integrity sha512-mYUYkAy6fPatVWtUeCV/qGeGL3IVucmdJOzeAEfwgCJDx8gP0JaW8jn6KQ5xDfPec31e0KXWn5EUOZMhquR1zA== + version "1.4.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" + integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== type-is@^1.6.16, type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" @@ -13443,15 +13535,6 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-loader@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -13625,9 +13708,9 @@ vfile-location@^2.0.0: integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== vfile-message@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.0.1.tgz#b9bcf87cb5525e61777e0c6df07e816a577588a3" - integrity sha512-gYmSHcZZUEtYpTmaWaFJwsuUD70/rTY4v09COp8TGtOkix6gGxb/a8iTQByIY9ciTk9GwAwIXd/J9OPfM4Bvaw== + version "3.0.2" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.0.2.tgz#db7eaebe7fecb853010f2ef1664427f52baf8f74" + integrity sha512-UUjZYIOg9lDRwwiBAuezLIsu9KlXntdxwG+nXnjuQAHvBpcX3x0eN8h+I7TkY5nkCXj+cWVp4ZqebtGBvok8ww== dependencies: "@types/unist" "^2.0.0" unist-util-stringify-position "^3.0.0" @@ -13818,17 +13901,16 @@ which-pm@2.0.0: path-exists "^4.0.0" which-typed-array@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.4.tgz#8fcb7d3ee5adf2d771066fba7cf37e32fe8711ff" - integrity sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA== + version "1.1.6" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.6.tgz#f3713d801da0720a7f26f50c596980a9f5c8b383" + integrity sha512-DdY984dGD5sQ7Tf+x1CkXzdg85b9uEel6nr4UkFg1LoE9OXv3uRuZhe5CoWdawhGACeFpEZXH8fFLQnDhbpm/Q== dependencies: - available-typed-arrays "^1.0.2" - call-bind "^1.0.0" - es-abstract "^1.18.0-next.1" + available-typed-arrays "^1.0.4" + call-bind "^1.0.2" + es-abstract "^1.18.5" foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.6" which@^1.2.9: version "1.3.1" @@ -14040,7 +14122,15 @@ zen-observable-ts@^0.8.21: tslib "^1.9.3" zen-observable "^0.8.0" -zen-observable@^0.8.0, zen-observable@^0.8.14: +zen-observable-ts@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" + integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== + dependencies: + "@types/zen-observable" "0.8.3" + zen-observable "0.8.15" + +zen-observable@0.8.15, zen-observable@^0.8.0: version "0.8.15" resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From 712bea2e86879913d036a7e3771ec05dc357ef87 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Tue, 17 Aug 2021 16:26:27 +1000 Subject: [PATCH 17/76] Release notes for 2021-08-17 release (#6345) * New release notes. * Update index.tsx * Update 2021-08-17.mdx * Update next-env.d.ts * Update index.mdx * Update 2021-08-17.mdx --- docs/next-env.d.ts | 3 ++ docs/pages/releases/2021-08-17.mdx | 74 ++++++++++++++++++++++++++++++ docs/pages/releases/index.mdx | 40 ++++++++-------- docs/pages/updates/index.tsx | 22 ++++++++- 4 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 docs/pages/releases/2021-08-17.mdx diff --git a/docs/next-env.d.ts b/docs/next-env.d.ts index f87ea7fa66a..6ab0ecc22f4 100644 --- a/docs/next-env.d.ts +++ b/docs/next-env.d.ts @@ -2,3 +2,6 @@ /// /// /// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/docs/pages/releases/2021-08-17.mdx b/docs/pages/releases/2021-08-17.mdx new file mode 100644 index 00000000000..1a5b5a3bfca --- /dev/null +++ b/docs/pages/releases/2021-08-17.mdx @@ -0,0 +1,74 @@ +import { Markdown, getStaticProps } from '../../components/Markdown'; +import { Emoji } from '../../components/primitives/Emoji'; + +# Release: 17th August 2021 + +A major milestone in the path to a `General Availability` status for **Keystone 6**, this release includes: + +- **A new and improved GraphQL API** +- Enhancements to Custom Admin UI Pages +- Better deletion notifications +- And more… + +**⚠️   This release contains breaking changes, please see below!** + +```json +"@keystone-ui/notice": "4.0.1", +"@keystone-ui/segmented-control": "4.0.2", +"@keystone-ui/toast": "4.0.2", +"@keystone-next/admin-ui-utils": "5.0.6", +"@keystone-next/auth": "31.0.0", +"@keystone-next/cloudinary": "6.0.6", +"@keystone-next/fields": "14.0.0", +"@keystone-next/fields-document": "8.0.0", +"@keystone-next/keystone": "24.0.0", +"@keystone-next/testing": "1.1.1", +"@keystone-next/types": "24.0.0", +"@keystone-next/utils": "1.0.4", +``` + +## A new & improved GraphQL API + +We’ve made the experience of working with Keystone’s GraphQL API easier to program and reason about: + +- **Queries:** the names of top-level queries are now easier to understand. We also removed deprecated and unused legacy features. +- **Filters:** the arguments used in queries have been updated to accept a filter object for each field, rather than having all the filter options available at the top level. +- **Mutations:** all generated CRUD mutations have the same names and return types, but their inputs have changed. +- **Input Types:** we’ve updated the input types used for relationship fields in `update` and `create` operations, removing obsolete options and making the syntax between the two operations easier to differentiate. + +#### Upgrade guidance + +We've [written a complete guide](https://keystonejs.com/updates/new-graphql-api) to the improvements we've made, and it includes [a checklist of the steps you need to take to upgrade your Keystone projects](https://keystonejs.com/updates/new-graphql-api#upgrade-checklist). Be sure to check it out! + +!> While there are a lot of changes to this API, if you approach the upgrade process systematically your experience should be pretty smooth. If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com) to get the help you need. + +Screen Shot 2021-08-17 at 11 28 56 am + +## Custom Admin UI Pages + +Our [Custom Admin UI Pages](https://keystonejs.com/docs/guides/custom-admin-ui-pages) guide has been expanded, with an example to make your custom pages look more like the Admin UI, as well as adding links to your custom pages from the Admin UI Navigation! + +Screen Shot 2021-08-17 at 11 30 39 am + +## Improved Deletion Notifications + +When items are deleted via the Admin UI, we now display all the items that were successfully deleted, and any that failed, instead of displaying multiple notifications without any context. + +Screen Shot 2021-08-17 at 11 04 47 am + +## Deeper GraphQL Errors + +A `config.graphql.debug` option has been added, which can be used to control whether debug information such as stack traces are included in the errors returned by the GraphQL API. + +## Prisma Update + +Updated Prisma dependencies from `2.27.0` to `2.29.0`, check out the [Prisma releases page](https://github.com/prisma/prisma/releases/tag/2.29.0) for more details. + +## Credits + +Added option for `Bearer` token auth when using session, thanks to [@gautamsi](https://github.com/gautamsi)! + +You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-08-17) on GitHub. + +export default ({ children, ...props }) => {children}; +export { getStaticProps } diff --git a/docs/pages/releases/index.mdx b/docs/pages/releases/index.mdx index 538727144f1..911bcd49c02 100644 --- a/docs/pages/releases/index.mdx +++ b/docs/pages/releases/index.mdx @@ -4,75 +4,79 @@ import { Status } from '../../components/primitives/Status'; # Release Notes -## 29th July 2021 +## 17th August 2021 -Custom **navigation**, **pages** and **logo** in this big **Admin UI** themed release! — [read more](/releases/2021-07-29) +A **major milestone** in the path to a General Availability status for Keystone 6 this release includes ** new and improved GraphQL API** and more. — [Read more](/releases/2021-08-17) + +## 29th July 2021 + +Custom **navigation**, **pages** and **logo** in this big **Admin UI** themed release! — [Read more](/releases/2021-07-29) ## 13th July 2021 -More examples, types, and UI rendering tweaks as we push forward towards a general availability release! — [read more](/releases/2021-07-13) +More examples, types, and UI rendering tweaks as we push forward towards a general availability release! — [Read more](/releases/2021-07-13) ## 30th June 2021 -We fixed an issue with `cloudinaryImage` and `relationship` fields. — [read more](/releases/2021-06-30) +We fixed an issue with `cloudinaryImage` and `relationship` fields. — [Read more](/releases/2021-06-30) ## 29th June 2021 -The ID Field option has been revamped with `cuid`, `uuid` and `autoincrement` options! — [read more](/releases/2021-06-29) +The ID Field option has been revamped with `cuid`, `uuid` and `autoincrement` options! — [Read more](/releases/2021-06-29) ## 28th June 2021 -A new package to help test the behaviour of your GraphQL API, a document field example, better error messages, accessibility updates and another Prisma update! — [read more](/releases/2021-06-28) +A new package to help test the behaviour of your GraphQL API, a document field example, better error messages, accessibility updates and another Prisma update! — [Read more](/releases/2021-06-28) ## 15th June 2021 -Keystone Next now has a new core , unblocking many of the features you’ve been waiting for! — [read more](/releases/2021-06-15) +Keystone Next now has a new core , unblocking many of the features you’ve been waiting for! — [Read more](/releases/2021-06-15) ## 2nd June 2021 -We have a new JSON field , a bunch of new learning resources, and plenty of under the hood optimisations in this big release. — [read more](/releases/2021-06-02) +We have a new JSON field , a bunch of new learning resources, and plenty of under the hood optimisations in this big release. — [Read more](/releases/2021-06-02) ## 19th May 2021 -Node updates and Admin UI has moved! — [read more](/releases/2021-05-19) +Node updates and Admin UI has moved! — [Read more](/releases/2021-05-19) ## 17th May 2021 -Apollo caching can now be configured for performance and a basic authentication example to get your started — [read more](/releases/2021-05-17) +Apollo caching can now be configured for performance and a basic authentication example to get your started — [Read more](/releases/2021-05-17) ## 11th May 2021 -A bunch of admin UI tweaks in this release , among other minor fixes — [read more](/releases/2021-05-11) +A bunch of admin UI tweaks in this release , among other minor fixes — [Read more](/releases/2021-05-11) ## 5th May 2021 -Aside from dependency updates , we added an `isIndexed` config option to the `text`, `integer`, `float`, `select`, and `timestamp` field types — [read more](/releases/2021-05-05) +Aside from dependency updates , we added an `isIndexed` config option to the `text`, `integer`, `float`, `select`, and `timestamp` field types — [Read more](/releases/2021-05-05) ## 3rd May 2021 -Files in Keystone Next ! This release involved a bunch of busywork behind the scenes in Keystone Next — [read more](/releases/2021-05-03) +Files in Keystone Next ! This release involved a bunch of busywork behind the scenes in Keystone Next — [Read more](/releases/2021-05-03) ## 20th April 2021 -Improvements to the Lists API, deprecating `resolveFields` — [read more](/releases/2021-04-20) +Improvements to the Lists API, deprecating `resolveFields` — [Read more](/releases/2021-04-20) ## 6th April 2021 -Controlled code demolition , Better pagination in Admin UI — [read more](/releases/2021-04-06) +Controlled code demolition , Better pagination in Admin UI — [Read more](/releases/2021-04-06) ## 30th March 2021 -Goodbye legacy code , Improved `select` field type , Squashed bugs — [read more](/releases/2021-03-30) +Goodbye legacy code , Improved `select` field type , Squashed bugs — [Read more](/releases/2021-03-30) ## 23rd March 2021 -Added support for SQLite with Prisma , Noteworthy bug-squashing — [read more](/releases/2021-03-23) +Added support for SQLite with Prisma , Noteworthy bug-squashing — [Read more](/releases/2021-03-23) ## 22nd March 2021 -Prisma migrations , Noteworthy bug-squashing — [read more](/releases/2021-03-22) +Prisma migrations , Noteworthy bug-squashing — [Read more](/releases/2021-03-22)
    diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index 92518a0fdd8..8c004183f9c 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -10,6 +10,7 @@ import { Alert } from '../../components/primitives/Alert'; import { Type } from '../../components/primitives/Type'; import { DocsPage } from '../../components/Page'; import { ArrowR } from '../../components/icons/ArrowR'; +import { Emoji } from '../../components/primitives/Emoji'; import { useMediaQuery } from '../../lib/media'; type TimelineProps = { @@ -165,7 +166,26 @@ export default function WhatsNew() { gap: 0, })} > - + + + A major milestone in the path to a General Availability status + for Keystone 6, we've just released a new and improved GraphQL API.{' '} + +
    +
    + We’ve made the experience of working with Keystone’s GraphQL API easier to program and + reason about: We've{' '} + written a complete guide to + the improvements we've made, and it includes a{' '} + + checklist of the steps you need to take to upgrade your Keystone projects + + . +
    +
    + Be sure to check it out! +
    + We're opening Admin UI up to support a more personal content experience. Now you can:
      From 46b2dc63f75ee46b2d4aaa063d1b0aa8e272b0b8 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Wed, 18 Aug 2021 08:16:51 +1000 Subject: [PATCH 18/76] Fixed markdown for bold styles (#6346) --- docs/pages/releases/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/releases/index.mdx b/docs/pages/releases/index.mdx index 911bcd49c02..bc09fae72e6 100644 --- a/docs/pages/releases/index.mdx +++ b/docs/pages/releases/index.mdx @@ -8,7 +8,7 @@ import { Status } from '../../components/primitives/Status'; -A **major milestone** in the path to a General Availability status for Keystone 6 this release includes ** new and improved GraphQL API** and more. — [Read more](/releases/2021-08-17) +A **major milestone** in the path to a General Availability status for Keystone 6 this release includes **new and improved GraphQL API** and more. — [Read more](/releases/2021-08-17) ## 29th July 2021 From 44d6ec184b62aa308d0449f9eb87ad34c15e8116 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 18 Aug 2021 09:45:28 +1000 Subject: [PATCH 19/76] Update wording on upgrade guide and release notes (#6353) --- docs/pages/releases/2021-08-17.mdx | 2 +- docs/pages/updates/new-graphql-api.mdx | 7 ++++--- tests/test-projects/crud-notifications/CHANGELOG.md | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/pages/releases/2021-08-17.mdx b/docs/pages/releases/2021-08-17.mdx index 1a5b5a3bfca..fff504f9081 100644 --- a/docs/pages/releases/2021-08-17.mdx +++ b/docs/pages/releases/2021-08-17.mdx @@ -40,7 +40,7 @@ We’ve made the experience of working with Keystone’s GraphQL API easier to p We've [written a complete guide](https://keystonejs.com/updates/new-graphql-api) to the improvements we've made, and it includes [a checklist of the steps you need to take to upgrade your Keystone projects](https://keystonejs.com/updates/new-graphql-api#upgrade-checklist). Be sure to check it out! -!> While there are a lot of changes to this API, if you approach the upgrade process systematically your experience should be pretty smooth. If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com) to get the help you need. +!> While there are a lot of changes to this API, we've put a lot of effort into making the upgrade process as smooth as possible. If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com) to get the help you need. Screen Shot 2021-08-17 at 11 28 56 am diff --git a/docs/pages/updates/new-graphql-api.mdx b/docs/pages/updates/new-graphql-api.mdx index 47c6b0afc89..06711c705cb 100644 --- a/docs/pages/updates/new-graphql-api.mdx +++ b/docs/pages/updates/new-graphql-api.mdx @@ -48,7 +48,7 @@ export const lists = createSchema({ ## Query -We’ve changed the names of our top-level queries easier understand. +We’ve changed the names of our top-level queries so they’re easier to understand. We also took this opportunity to remove deprecated and unused legacy features. ### Changes @@ -138,7 +138,8 @@ tasks( ) { id } ``` -There is a one-to-one correspondence between the old filters and the new filters, so you can make a simple systematic set of changes to bring your filters up to date. +There is a one-to-one correspondence between the old filters and the new filters. +No filter functionality has been removed or added, however the individual filters are now in a nested object, and the names have changed from `snake_case` to `camelCase`. ?> **Note:** The old filter syntax used `{ fieldName: value }` to test for equality. The new syntax requires you to make this explicit, and write `{ fieldName: { equals: value} }`. @@ -386,7 +387,7 @@ input TagRelateToManyForCreateInput { ## Upgrade Checklist -While there are a lot of changes to this API, if you approach the upgrade process systematically your experience should be pretty smooth. If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com/) to get the help you need. +While there are a lot of changes to this API, we've put a lot of effort into making the upgrade process as smooth as possible. If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com/) to get the help you need. ?> Before you begin: check that your project doesn't rely on any of the features we've marked as deprecated in this document, or the `search` argument to filters. If you do, apply the recommended substitute. diff --git a/tests/test-projects/crud-notifications/CHANGELOG.md b/tests/test-projects/crud-notifications/CHANGELOG.md index 4315359a821..d1ab06577e5 100644 --- a/tests/test-projects/crud-notifications/CHANGELOG.md +++ b/tests/test-projects/crud-notifications/CHANGELOG.md @@ -1,6 +1,7 @@ # @keystone-next/test-projects-crud-notifications ## 0.0.3 + ### Patch Changes - Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: From cdde50874fb1c8e71cc4c54ccbe88690241af629 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Thu, 19 Aug 2021 11:16:55 +1000 Subject: [PATCH 20/76] Updates nav additions (#6366) * Relocated "K5 vs K6" guidance * Updated sidebar navigation content for `/updates` --- docs/components/docs/Navigation.tsx | 32 ++++++++++++++++++- docs/pages/docs/guides/index.tsx | 8 ----- docs/pages/docs/index.tsx | 2 +- docs/pages/updates/index.tsx | 4 +-- .../keystone-5-vs-keystone-6-preview.mdx | 2 +- docs/pages/updates/roadmap.tsx | 2 +- docs/redirects.js | 7 +++- 7 files changed, 42 insertions(+), 15 deletions(-) rename docs/pages/{docs/guides => updates}/keystone-5-vs-keystone-6-preview.mdx (98%) diff --git a/docs/components/docs/Navigation.tsx b/docs/components/docs/Navigation.tsx index f854aea01c7..75264b6f4b6 100644 --- a/docs/components/docs/Navigation.tsx +++ b/docs/components/docs/Navigation.tsx @@ -10,6 +10,7 @@ import { useMediaQuery } from '../../lib/media'; import { useHeaderContext } from '../Header'; import { Badge } from '../primitives/Badge'; import { Type } from '../primitives/Type'; +import { Emoji } from '../primitives/Emoji'; type SectionProps = { label: string; children: ReactNode }; export function Section({ label, children }: SectionProps) { @@ -133,7 +134,6 @@ export function DocsNavigation() { Walkthroughs Examples
      - Keystone 5 vs 6 Command Line Relationships @@ -214,6 +214,36 @@ export function UpdatesNavigation({ releases = [] }: { releases: string[] }) { ))}
      ) : null} +
      + + +   New GraphQL API + + + +   Customisable Admin UI + + + +   Jed’s Prisma Day Talk + + + +   New Core + + + +   New Examples Collection + + + +   Keystone 5 vs 6 + +
      ); } diff --git a/docs/pages/docs/guides/index.tsx b/docs/pages/docs/guides/index.tsx index 57c52da5d11..5d6876a84fa 100644 --- a/docs/pages/docs/guides/index.tsx +++ b/docs/pages/docs/guides/index.tsx @@ -35,14 +35,6 @@ export default function Docs() { gap: 'var(--space-xlarge)', })} > - - We’re transitioning to Keystone 6 soon. If you’re wondering which version to start a new - project with today, this guide is for you. - Keystone’s CLI helps you develop, build, and deploy projects. This guide explains all you need to standup a new backend in the terminal. diff --git a/docs/pages/docs/index.tsx b/docs/pages/docs/index.tsx index 7b7408e6ae0..b20d962eca3 100644 --- a/docs/pages/docs/index.tsx +++ b/docs/pages/docs/index.tsx @@ -101,7 +101,7 @@ export default function Docs() { We’re graduating Keystone 6 soon. If you’re wondering which version to start a new project with today, this guide is for you. diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index 8c004183f9c..e10cf09a19b 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -167,7 +167,7 @@ export default function WhatsNew() { })} > - + A major milestone in the path to a General Availability status for Keystone 6, we've just released a new and improved GraphQL API.{' '} @@ -412,7 +412,7 @@ export default function WhatsNew() { Keystone 5 is now in maintenance mode while we focus all our efforts on building Keystone diff --git a/docs/pages/docs/guides/keystone-5-vs-keystone-6-preview.mdx b/docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx similarity index 98% rename from docs/pages/docs/guides/keystone-5-vs-keystone-6-preview.mdx rename to docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx index 0ded46e55ad..75bae6756d5 100644 --- a/docs/pages/docs/guides/keystone-5-vs-keystone-6-preview.mdx +++ b/docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx @@ -1,4 +1,4 @@ -import { Markdown } from '../../../components/Markdown'; +import { Markdown } from '../../components/Markdown'; # Keystone 5 vs 6, which should you use? diff --git a/docs/pages/updates/roadmap.tsx b/docs/pages/updates/roadmap.tsx index 6a66741b49b..a469b123120 100644 --- a/docs/pages/updates/roadmap.tsx +++ b/docs/pages/updates/roadmap.tsx @@ -240,7 +240,7 @@ export default function Roadmap() { {/* If you're assessing whether to start a project today on Keystone 5 or 6, check our{' '} - + Comparison Page */} diff --git a/docs/redirects.js b/docs/redirects.js index 52a8281777f..e4beb19507c 100644 --- a/docs/redirects.js +++ b/docs/redirects.js @@ -106,7 +106,12 @@ const ORIGINAL_NEXT = [ const CURRENT = [ { source: '/docs/guides/keystone-5-vs-keystone-next', - destination: '/docs/guides/keystone-5-vs-keystone-6-preview', + destination: '/updates/keystone-5-vs-keystone-6-preview', + permanent: true, + }, + { + source: '/docs/guides/keystone-5-vs-keystone-6-preview', + destination: '/updates/keystone-5-vs-keystone-6-preview', permanent: true, }, ]; From d43a1d8d31b984d246444c91e16a7849a90ce1a0 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Fri, 20 Aug 2021 08:22:26 +1000 Subject: [PATCH 21/76] Update new-graphql-api.mdx (#6375) --- docs/pages/updates/new-graphql-api.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/updates/new-graphql-api.mdx b/docs/pages/updates/new-graphql-api.mdx index 06711c705cb..bb1b40223af 100644 --- a/docs/pages/updates/new-graphql-api.mdx +++ b/docs/pages/updates/new-graphql-api.mdx @@ -143,7 +143,7 @@ No filter functionality has been removed or added, however the individual filter ?> **Note:** The old filter syntax used `{ fieldName: value }` to test for equality. The new syntax requires you to make this explicit, and write `{ fieldName: { equals: value} }`. -!> See the [Filters Guide](/docs/guides/filters) for a detailed walk through the new filtering syntex. +!> See the [Filters Guide](/docs/guides/filters) for a detailed walk through the new filtering syntax. !> See the [API docs](/docs/apis/filters) for a comprehensive list of all the new filters for each field type. From e7ed4d3e547f6d5c38d5e123581ca302b34f0b45 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Fri, 20 Aug 2021 09:12:22 +1000 Subject: [PATCH 22/76] Updated URLs (#6374) --- docs/pages/docs/guides/custom-fields.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/docs/guides/custom-fields.mdx b/docs/pages/docs/guides/custom-fields.mdx index 8ccae1ba737..8ae9e65d04f 100644 --- a/docs/pages/docs/guides/custom-fields.mdx +++ b/docs/pages/docs/guides/custom-fields.mdx @@ -12,9 +12,9 @@ There are two parts to a field type: - The **frontend** portion which defines how the field looks and behaves in the Admin UI. The general approach to creating a custom field type is to take an existing field type and make the appropriate changes for your use case. -In this guide we're going to create a field type `myInt` which recreates the [`integer`](https://github.com/keystonejs/keystone/tree/master/packages/fields/src/types/integer) field type. +In this guide we're going to create a field type `myInt` which recreates the [`integer`](https://github.com/keystonejs/keystone/tree/master/packages/keystone/src/fields/types/integer) field type. -!> For inspiration, see [the source for the fields that Keystone provides](https://github.com/keystonejs/keystone/tree/master/packages/fields/src/types) and the [Custom Fields](https://github.com/keystonejs/keystone/tree/master/examples/custom-field) example project. +!> For inspiration, see [the source for the fields that Keystone provides](https://github.com/keystonejs/keystone/tree/master/packages/keystone/src/fields/types) and the [Custom Fields](https://github.com/keystonejs/keystone/tree/master/examples/custom-field) example project. ## Backend From 67e0756a7736b09f0917426bc88214a1e88b9ceb Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Fri, 20 Aug 2021 16:14:34 +1000 Subject: [PATCH 23/76] Tweaking docs for Next.js walkthrough for latest version (#6383) * Tweaking docs for Next.js walkthrough. * Update next-env.d.ts --- .../embedded-mode-with-sqlite-nextjs.mdx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx index fea513eff8b..34cda79bccd 100644 --- a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx +++ b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx @@ -38,11 +38,15 @@ Here's what we're going to do: ## Setup a Next.js app -Create a basic Next.js project with the `--typescript` option in an empty directory. +x> **Warning:** We normally advise to set up a new Next.js app with `yarn create next-app --typescript my-project`, however this will install Next.js `11.x`. This version isn't compatible with this guide until we upgrade Keystone's Next.js internals to `11.x`. + +x> To continue, you'll need to use Next.js `10.x` until this upgrade is completed. We've set up a repository below using Next.js `10.x` you can clone in the mean time. + +Clone the basic Next.js project below. ```bash -yarn create next-app --typescript my-project -cd my-project +git clone https://github.com/keystonejs/embedded-mode-with-sqlite-nextjs +cd embedded-mode-with-sqlite-nextjs ``` !> Keystone 6 has great TypeScript support. Including it in your project will make it easier to use Keystone’s APIs later. @@ -256,7 +260,7 @@ export async function getStaticProps({ params, }: GetStaticPropsContext) { const [post] = await lists.Post.findMany({ - where: { slug: params!.slug as string }, + where: { slug: { equals: params!.slug as string } }, query: 'id title content', }); return { props: { post } }; From a3fb2eac382953227e71ab5e6dde9a5f7ad18007 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Mon, 23 Aug 2021 09:13:17 +1000 Subject: [PATCH 24/76] Added upgrade notices to GraphQL API related pages (#6387) --- docs/pages/docs/apis/filters.mdx | 2 ++ docs/pages/docs/apis/graphql.mdx | 2 ++ docs/pages/docs/guides/filters.mdx | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/pages/docs/apis/filters.mdx b/docs/pages/docs/apis/filters.mdx index 5e58fc12cad..a23a630431c 100644 --- a/docs/pages/docs/apis/filters.mdx +++ b/docs/pages/docs/apis/filters.mdx @@ -2,6 +2,8 @@ import { Markdown } from '../../../components/Markdown'; # Query Filter API +?> We recently improved this API so it’s easier to program and reason about. If you were using it prior to August 17th 2021, [read this guide](/updates/new-graphql-api) for info on how to upgrade. + Each field type provides its own set of filters which can be used with [queries](./graphql#all-users). This page lists all the filters available for each field type. For more details on how to use filters in queries please consult to the [GraphQL Queries - Filters](../guides/filters) guide. diff --git a/docs/pages/docs/apis/graphql.mdx b/docs/pages/docs/apis/graphql.mdx index 37c9099195d..8c03f57431b 100644 --- a/docs/pages/docs/apis/graphql.mdx +++ b/docs/pages/docs/apis/graphql.mdx @@ -2,6 +2,8 @@ import { Markdown } from '../../../components/Markdown'; # GraphQL API +?> We recently improved this API so it’s easier to program and reason about. If you were using it prior to August 17th 2021, [read this guide](/updates/new-graphql-api) for info on how to upgrade. + Keystone generates a CRUD (create, read, update, delete) GraphQL API based on the [schema](./schema) definition provided in the system [config](./config). Consider the following system definition: diff --git a/docs/pages/docs/guides/filters.mdx b/docs/pages/docs/guides/filters.mdx index 869cb8acfe3..52859c236d3 100644 --- a/docs/pages/docs/guides/filters.mdx +++ b/docs/pages/docs/guides/filters.mdx @@ -2,6 +2,8 @@ import { Markdown } from '../../../components/Markdown'; # GraphQL Queries - Filters +?> We recently improved our GraphQL API so it’s easier to program and reason about. If you were using it prior to August 17th 2021, [read this guide](/updates/new-graphql-api) for info on how to upgrade. + Keystone provides a powerful GraphQL API for querying the data in your system. At the core of this API are **query filters**. This guide will show you how to use filters to get data you need. From 31a20648f4dc254ecb1dc2ec816a72c707d5a901 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Mon, 23 Aug 2021 09:30:10 +1000 Subject: [PATCH 25/76] Fixed link color inconsistency (#6388) --- docs/lib/prose-lite.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/lib/prose-lite.ts b/docs/lib/prose-lite.ts index d96b0595a7c..fbf5edd053d 100644 --- a/docs/lib/prose-lite.ts +++ b/docs/lib/prose-lite.ts @@ -7,15 +7,15 @@ export const proseStyles = { content: '""', }, a: { - color: 'var(--text)', textDecoration: 'underline', fontWeight: 500, + color: 'inherit', }, 'a:hover': { color: 'var(--link)', }, strong: { - color: 'var(--text)', + color: 'inherit', fontWeight: 600, }, 'ol[type="A"], ol[type="A" s]': { From 80f122fcd5050b7643f05a9826c3426b7a5faa53 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Mon, 23 Aug 2021 11:50:20 +1000 Subject: [PATCH 26/76] Add note to use `yarn` in the embedded Next.js guide (#6384) * Tweaking docs for Next.js walkthrough. * Update next-env.d.ts * Update embedded-mode-with-sqlite-nextjs.mdx --- .../docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx index 34cda79bccd..74220a2f128 100644 --- a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx +++ b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx @@ -49,6 +49,8 @@ git clone https://github.com/keystonejs/embedded-mode-with-sqlite-nextjs cd embedded-mode-with-sqlite-nextjs ``` +Then run `yarn` to install the dependencies. + !> Keystone 6 has great TypeScript support. Including it in your project will make it easier to use Keystone’s APIs later. Delete the `/pages/api` directory. We’ll add a GraphQL API later in the tutorial. Your `/pages` directory should now look like this: From 2da90e0a6ddf3614ce7f608bb8beeca07d66c1a1 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Tue, 24 Aug 2021 16:19:59 +1000 Subject: [PATCH 27/76] [WIP] Related content links (#6360) * WIP: get well in bottom of page * New RelatedContent component. * Added related content for POC * Added more related content cards * Updated guides index * Styles fix for inline code within component Co-authored-by: Thomas Walker --- docs/components/RelatedContent.tsx | 24 +++++++++ docs/components/primitives/Well.tsx | 4 +- docs/pages/docs/apis/auth.mdx | 13 +++++ docs/pages/docs/apis/config.mdx | 14 +++++ docs/pages/docs/apis/context.mdx | 20 +++++++ docs/pages/docs/apis/db-items.mdx | 20 +++++++ docs/pages/docs/apis/fields.mdx | 22 +++++++- docs/pages/docs/apis/filters.mdx | 13 +++++ docs/pages/docs/apis/graphql.mdx | 20 +++++++ docs/pages/docs/apis/hooks.mdx | 13 +++++ docs/pages/docs/apis/list-items.mdx | 19 +++++++ docs/pages/docs/apis/schema.mdx | 27 ++++++++++ docs/pages/docs/apis/session.mdx | 21 ++++++++ docs/pages/docs/guides/cli.mdx | 13 +++++ .../docs/guides/custom-admin-ui-logo.mdx | 28 ++++++++++ .../guides/custom-admin-ui-navigation.mdx | 27 ++++++++++ .../docs/guides/custom-admin-ui-pages.mdx | 29 +++++++++++ docs/pages/docs/guides/custom-fields.mdx | 17 +++++- .../pages/docs/guides/document-field-demo.mdx | 22 ++++++++ docs/pages/docs/guides/document-fields.mdx | 22 ++++++++ docs/pages/docs/guides/filters.mdx | 13 +++++ docs/pages/docs/guides/hooks.mdx | 10 ++++ docs/pages/docs/guides/index.tsx | 52 +++++++++++++++++-- docs/pages/docs/guides/relationships.mdx | 13 +++++ docs/pages/docs/guides/testing.mdx | 28 ++++++++++ docs/pages/docs/guides/virtual-fields.mdx | 21 ++++++++ .../embedded-mode-with-sqlite-nextjs.mdx | 13 +++++ ...tting-started-with-create-keystone-app.mdx | 26 ++++++++++ 28 files changed, 558 insertions(+), 6 deletions(-) create mode 100644 docs/components/RelatedContent.tsx diff --git a/docs/components/RelatedContent.tsx b/docs/components/RelatedContent.tsx new file mode 100644 index 00000000000..425b4cc882b --- /dev/null +++ b/docs/components/RelatedContent.tsx @@ -0,0 +1,24 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/react'; +import { ReactNode } from 'react'; + +import { useMediaQuery } from '../lib/media'; + +export function RelatedContent({ children }: { children: ReactNode }) { + const mq = useMediaQuery(); + + return ( +
      a > p > p > code': { + textDecoration: 'none', + }, + })} + > + {children} +
      + ); +} diff --git a/docs/components/primitives/Well.tsx b/docs/components/primitives/Well.tsx index a08cff47dee..c087f5b7213 100644 --- a/docs/components/primitives/Well.tsx +++ b/docs/components/primitives/Well.tsx @@ -27,6 +27,7 @@ export function Well({ grad = 'grad1', heading, href, children, ...props }: Well color: 'var(--text)', overflow: 'hidden', transition: 'box-shadow 0.2s ease, transform 0.2s ease, padding 0.2s ease', + textDecoration: 'none !important', ':before': { content: '""', position: 'absolute', @@ -47,8 +48,9 @@ export function Well({ grad = 'grad1', heading, href, children, ...props }: Well as="h2" look="heading20bold" css={{ - margin: '0 0 1rem 0', + margin: '0 0 1rem 0 !important', paddingRight: '2rem', + fontSize: '1.25rem !important', }} > {heading} → diff --git a/docs/pages/docs/apis/auth.mdx b/docs/pages/docs/apis/auth.mdx index bca3897dbd6..3c12f781d46 100644 --- a/docs/pages/docs/apis/auth.mdx +++ b/docs/pages/docs/apis/auth.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Authentication API @@ -475,4 +477,15 @@ If the token has expired the value `{ code: TOKEN_EXPIRED, message: 'The auth to If the token is valid then the session handler will start a new session and return the encoded session cookie data as `sessionToken`. The authenticated item will be returned as `item`. +## Related resources + + + + Adds password-based authentication to the Task Manager starter project. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/config.mdx b/docs/pages/docs/apis/config.mdx index 3b6e7618400..249781d2507 100644 --- a/docs/pages/docs/apis/config.mdx +++ b/docs/pages/docs/apis/config.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # System Configuration API @@ -404,4 +407,15 @@ Options: - `generateNextGraphqlAPI`: Creates a file at `node_modules/.keystone/next/graphql-api` with `default` and `config` exports that can be re-exported in a Next API route - `generateNodeAPI`: Creates a file at `node_modules/.keystone/api` with a `lists` export +## Related resources + + + + The API to configure your options used with the list function. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/context.mdx b/docs/pages/docs/apis/context.mdx index 665c62b2c5d..2c06bbda7e7 100644 --- a/docs/pages/docs/apis/context.mdx +++ b/docs/pages/docs/apis/context.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # Context API @@ -161,4 +164,21 @@ They will be removed in future releases. `gqlNames`: A function which takes a `listKey` and returns an object containing the GraphQL query, mutation and type names related to that list. +## Related resources + + + + A programmatic API for running CRUD operations against your GraphQL API. For each list in your system you get an API at context.lists.<listName> + + + The API for running CRUD operations against the internal GraphQL resolvers in your system. It returns internal item objects, which can be returned from GraphQL resolvers. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/db-items.mdx b/docs/pages/docs/apis/db-items.mdx index e857f995535..375ebabca99 100644 --- a/docs/pages/docs/apis/db-items.mdx +++ b/docs/pages/docs/apis/db-items.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # Database Items API @@ -140,4 +143,21 @@ const users = await context.db.lists.User.deleteMany({ }); ``` +## Related resources + + + + A programmatic API for running CRUD operations against your GraphQL API. For each list in your system you get an API at context.lists.<listName>. + + + The API for run-time functionality in your Keystone system. Use it to write business logic for access control, hooks, testing, GraphQL schema extensions, and more. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index 88d5c0ef067..3f5daecb149 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # Fields API @@ -732,4 +735,21 @@ export default config({ }); ``` -export default ({ children }) => {children}; +## Related resources + + + + The API to configure your options used with the list() function. + + + A complete CRUD (create, read, update, delete) GraphQL API derived from the list and field names you configure in your system. + + + +export default ({ children }) => {children} diff --git a/docs/pages/docs/apis/filters.mdx b/docs/pages/docs/apis/filters.mdx index a23a630431c..dabc8c8c8c9 100644 --- a/docs/pages/docs/apis/filters.mdx +++ b/docs/pages/docs/apis/filters.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Query Filter API @@ -149,4 +151,15 @@ The `file` field type does not support filters. The `image` field type does not support filters. +## Related resources + + + + Query filters are an integral part of Keystone’s powerful GraphQL APIs. This guide will show you how to use filters to get the data you need from your system. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/graphql.mdx b/docs/pages/docs/apis/graphql.mdx index 8c03f57431b..f4ef99a7344 100644 --- a/docs/pages/docs/apis/graphql.mdx +++ b/docs/pages/docs/apis/graphql.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # GraphQL API @@ -409,4 +412,21 @@ type User { } ``` +## Related resources + + + + The API to configure your options used with the list() function. + + + The API to configure all the parts parts of your Keystone system. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/hooks.mdx b/docs/pages/docs/apis/hooks.mdx index bf1537c7849..3241396d799 100644 --- a/docs/pages/docs/apis/hooks.mdx +++ b/docs/pages/docs/apis/hooks.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Hooks API @@ -438,4 +440,15 @@ The data resolving steps are applied in the following order: 5. Field hooks (user defined): A `resolveInput` field hook can return a new value for its field, which will the current field value on `resolvedData`. 6. List hooks (user defined): A `resolveInput` list hook can return a new value for the entire `resolvedData` object. +## Related resources + + + + Learn how to use Hooks within your schema to extend Keystone’s powerful CRUD GraphQL APIs with your own business logic. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/list-items.mdx b/docs/pages/docs/apis/list-items.mdx index 12630497fd1..b0006bf5a1f 100644 --- a/docs/pages/docs/apis/list-items.mdx +++ b/docs/pages/docs/apis/list-items.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # List Items API @@ -144,4 +146,21 @@ const users = await context.lists.User.deleteMany({ }); ``` +## Related resources + + + + The API for run-time functionality in your Keystone system. Use it to write business logic for access control, hooks, testing, GraphQL schema extensions, and more. + + + The API for running CRUD operations against the internal GraphQL resolvers in your system. It returns internal item objects, which can be returned from GraphQL resolvers. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/schema.mdx b/docs/pages/docs/apis/schema.mdx index 176ea2e956b..8b09c020d83 100644 --- a/docs/pages/docs/apis/schema.mdx +++ b/docs/pages/docs/apis/schema.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Schema API @@ -207,4 +209,29 @@ export default config({ The `description` option defines a string which will be used as a description in the Admin UI and GraphQL API docs. This option can be individually overridden by the `graphql.description` or `ui.description` options. +## Related resources + + + + Defines the names, types, and configuration of Keystone fields. See all the fields and the configuration options they accept. + + + The API to configure all the parts parts of your Keystone system. + + + A basic Blog schema with Posts and Authors. Use this as a starting place for learning how to use Keystone. It’s also a starter for other feature projects. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/session.mdx b/docs/pages/docs/apis/session.mdx index 01c514b7921..69073de4586 100644 --- a/docs/pages/docs/apis/session.mdx +++ b/docs/pages/docs/apis/session.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Session API @@ -122,4 +124,23 @@ If you configure your Keystone session with session management then the [`Keysto The `startSession` and `endSession` functions will be used by [authentication mutations](./auth) to start and end authenticated sessions. These mutations will set the value of `session` to include the values `{ listKey, itemId }`. +## Related resources + + + + The API to configure all the parts parts of your Keystone system. + + + Adds password-based authentication to the Task Manager starter project. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/cli.mdx b/docs/pages/docs/guides/cli.mdx index d20b45eb04b..53ceebb1db0 100644 --- a/docs/pages/docs/guides/cli.mdx +++ b/docs/pages/docs/guides/cli.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Command Line @@ -186,4 +188,15 @@ yarn keystone-next start - If you promote your build through separate environments in a pipeline (e.g testing → staging → production) you should run migrations during the **promote** step and **not** as part of the build script. - It is important you do **not run migrations against your production database from staging builds**. If you have staging or preview environments set up in production, make sure they are not pointed to your production database. +## Related resources + + + + How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL API playground. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/custom-admin-ui-logo.mdx b/docs/pages/docs/guides/custom-admin-ui-logo.mdx index 00c11d9d90e..e363a2cec0c 100644 --- a/docs/pages/docs/guides/custom-admin-ui-logo.mdx +++ b/docs/pages/docs/guides/custom-admin-ui-logo.mdx @@ -1,6 +1,8 @@ import { ComingSoon } from '../../../components/docs/ComingSoon'; import { Markdown } from '../../../components/Markdown'; import { Alert } from '../../../components/primitives/Alert' +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Custom Admin UI Logo @@ -46,4 +48,30 @@ Of course this is purely a recommendation, if you would prefer to roll your own Once you've added your custom logo component you should see it rendered out in the Admin UI. ![image of Admin UI with custom logo](/assets/guides/custom-admin-ui-logo/custom-logo-result.png) +## Related resources + + + + Adds a custom logo component in the Admin UI. Builds on the Task Manager starter project. + + + Learn how to create your own custom Navigation components in Keytone’s Admin UI. + + + Learn how to add your own custom pages to Keystone’s Admin UI. + + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/custom-admin-ui-navigation.mdx b/docs/pages/docs/guides/custom-admin-ui-navigation.mdx index f37ab3e2da3..2afc212c67f 100644 --- a/docs/pages/docs/guides/custom-admin-ui-navigation.mdx +++ b/docs/pages/docs/guides/custom-admin-ui-navigation.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Custom Admin UI Navigation @@ -304,4 +306,29 @@ type NavItemProps = { By default the `isSelected` value will be evaluated by the condition `router.pathname === href`. Pass in `isSelected` if you have a custom condition or would like more granular control over the "selected" state of Navigation items. +## Related resources + + + + Adds a custom navigation component to the Admin UI. Builds on the Task Manager starter project. + + + Learn how to add your own custom logo to Keystone’s Admin UI. + + + Learn how to add your own custom pages to Keystone’s Admin UI. + + + export default ({ children }) => {children} diff --git a/docs/pages/docs/guides/custom-admin-ui-pages.mdx b/docs/pages/docs/guides/custom-admin-ui-pages.mdx index 30af0ff1f6f..1bb1b559ae8 100644 --- a/docs/pages/docs/guides/custom-admin-ui-pages.mdx +++ b/docs/pages/docs/guides/custom-admin-ui-pages.mdx @@ -1,6 +1,8 @@ import { ComingSoon } from '../../../components/docs/ComingSoon'; import { Markdown } from '../../../components/Markdown'; import { Alert } from '../../../components/primitives/Alert'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Custom Admin UI Pages @@ -9,6 +11,8 @@ import { Alert } from '../../../components/primitives/Alert'; In this guide we'll show you how to add custom pages to the Keystone Admin UI. As the Admin UI is built on top of [Next.js](https://nextjs.org/docs/basic-features/pages), it exposes the same pages directory for adding custom pages. +## Getting started + To create a custom page, ensure that the `admin/pages` directory exists in the root of your Keystone Project. Much like with Next.js, all files in this directory will be added as routes to the Admin UI. The default export of every file in this directory is expected to be a valid React Component rendered out as the contents of the route. @@ -173,4 +177,29 @@ export default function CustomPage () { Using `emotion` for styling is purely a recommendation, if you would prefer to use another css-in-js or css solution for your custom component please feel free to. This may require additional configuration currently outside of the scope of this guide. +## Related resources + + + + Adds a custom page in the Admin UI. Builds on the Task Manager starter project. + + + Learn how to add your own custom logo to Keystone’s Admin UI. + + + Learn how to create your own custom Navigation components in Keytone’s Admin UI. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/custom-fields.mdx b/docs/pages/docs/guides/custom-fields.mdx index 8ae9e65d04f..ade3bf42fe2 100644 --- a/docs/pages/docs/guides/custom-fields.mdx +++ b/docs/pages/docs/guides/custom-fields.mdx @@ -1,5 +1,7 @@ -import { ComingSoon } from '../../../components/docs/ComingSoon'; import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # Custom Fields @@ -223,4 +225,17 @@ export const CardValue: CardValueComponent = ({ item, field }) => { }; ``` +## Related resources + + + + Adds a custom field type based on the integer field type which lets users rate items on a 5-star scale. Builds on the Blog starter project. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/document-field-demo.mdx b/docs/pages/docs/guides/document-field-demo.mdx index 5f906a89733..d80abb27b26 100644 --- a/docs/pages/docs/guides/document-field-demo.mdx +++ b/docs/pages/docs/guides/document-field-demo.mdx @@ -9,6 +9,9 @@ import { DocumentFeaturesProvider, } from '../../../components/docs/DocumentEditorDemo'; import Intro from './_doc-field-intro.mdx'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; ## Configure the demo @@ -51,3 +54,22 @@ export default ({ children }) => { ); }; + +## Related resources + + + + Keystone’s document field is a highly customisable rich text editor that stores content as structured JSON. Learn how to configure it and incorporate your own custom React components. + + + Illustrates how to configure document fields in your Keystone system and render their data in a frontend application. Builds on the Blog starter project. + + diff --git a/docs/pages/docs/guides/document-fields.mdx b/docs/pages/docs/guides/document-fields.mdx index 9b2b5da7aa7..fcfe22e204d 100644 --- a/docs/pages/docs/guides/document-fields.mdx +++ b/docs/pages/docs/guides/document-fields.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # How To Use Document Fields @@ -676,4 +679,23 @@ const componentBlockRenderers: InferRenderersForComponentBlocks; ``` +## Related resources + + + + Illustrates how to configure document fields in your Keystone system and render their data in a frontend application. Builds on the Blog starter project. + + + Test drive the many features of Keystone’s Document field on this website. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/filters.mdx b/docs/pages/docs/guides/filters.mdx index 52859c236d3..bca50788605 100644 --- a/docs/pages/docs/guides/filters.mdx +++ b/docs/pages/docs/guides/filters.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # GraphQL Queries - Filters @@ -173,4 +175,15 @@ For example, to find all the people which have `some` posts with the label `"Hel } ``` +## Related resources + + + + The complete list of filters available to Keystone field types. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/hooks.mdx b/docs/pages/docs/guides/hooks.mdx index fbfb9eff43e..5efc910c478 100644 --- a/docs/pages/docs/guides/hooks.mdx +++ b/docs/pages/docs/guides/hooks.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Hooks @@ -222,4 +224,12 @@ export default config({ See the [Hooks API](../apis/hooks) for the details of all the arguments available for all the different hook functions. +## Related resources + + + + The complete reference for executing code at different stages of the mutation lifecycle + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/index.tsx b/docs/pages/docs/guides/index.tsx index 5d6876a84fa..2da2b2dc68d 100644 --- a/docs/pages/docs/guides/index.tsx +++ b/docs/pages/docs/guides/index.tsx @@ -47,14 +47,60 @@ export default function Docs() { Query filters are an integral part of Keystone’s powerful GraphQL APIs. This guide will show you how to use filters to get the data you need from your system.
      + + Learn how to use Hooks within your schema to extend Keystone’s powerful CRUD GraphQL APIs + with your own business logic. + Keystone’s document field is a highly customisable rich text editor that stores content as structured JSON. Learn how to configure it and incorporate your own custom React components. - - Learn how to use Hooks within your schema to extend Keystone’s powerful CRUD GraphQL APIs - with your own business logic. + + Test drive the many features of Keystone’s Document field on this website. + + + Learn how to define your own custom field types in Keystone, with customisable backend + data structure, and Admin UI appearance. + + + Learn how to test the behaviour of your Keystone system to ensure it does what you expect. + + + Virtual fields offer a powerful way to extend your GraphQL API. This guide introduces the + syntax and shows you how start simply and end up with a complex result. + +
    + + Admin UI Customisation + +
    + + Learn how to add your own custom logo to Keystone’s Admin UI. + + + Learn how to create your own custom Navigation components in Keytone’s Admin UI. + + + Learn how to add your own custom pages to Keystone’s Admin UI.
    diff --git a/docs/pages/docs/guides/relationships.mdx b/docs/pages/docs/guides/relationships.mdx index cd5ac552c5e..6d546873fc1 100644 --- a/docs/pages/docs/guides/relationships.mdx +++ b/docs/pages/docs/guides/relationships.mdx @@ -1,5 +1,7 @@ import { Emoji } from '../../../components/primitives/Emoji'; import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Understanding Relationships @@ -314,4 +316,15 @@ export default config({ Keystone relationships are managed using the [relationship](../apis/fields#relationship) field type. They can be configured as one-sided or two-sided by the `ref` config option. Their cardinality can be set using the `many` flag. Keystone gives you the flexibility to choose what you want based on what you need to achieve. +## Related resources + + + + Defines the names, types, and configuration of Keystone fields. See all the fields and the configuration options they accept. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/testing.mdx b/docs/pages/docs/guides/testing.mdx index e70afacb7e0..ae34ac045b6 100644 --- a/docs/pages/docs/guides/testing.mdx +++ b/docs/pages/docs/guides/testing.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; # Testing @@ -234,4 +237,29 @@ describe('Example tests using test environment', () => { }); ``` +## Related resources + + + + Shows you how to write tests against the GraphQL API to your Keystone system. Builds on the Authentication example project. + + + The API for run-time functionality in your Keystone system. Use it to write business logic for access control, hooks, testing, GraphQL schema extensions, and more. + + + A programmatic API for running CRUD operations against your GraphQL API. For each list in your system you get an API at context.lists.<listName>. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/guides/virtual-fields.mdx b/docs/pages/docs/guides/virtual-fields.mdx index e1a697ee4f7..270c279b887 100644 --- a/docs/pages/docs/guides/virtual-fields.mdx +++ b/docs/pages/docs/guides/virtual-fields.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # Virtual Fields @@ -315,4 +317,23 @@ Another way to address this is to use a [scalar field](../apis/fields#scalar-typ The other main consideration is that it is not possible to filter on a virtual field, as each item calcutes its value dynamically, rather than having it stored in the database. Using a pre-calculated scalar field is the best solution to use if you need filtering for your field. +## Related resources + + + + A demo project that shows you how to add virtual fields to a Keystone list. + + + A virtual field represents a value which is computed a read time, rather than stored in the database. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx index 74220a2f128..cec664c2356 100644 --- a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx +++ b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx @@ -1,4 +1,6 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; # How to embed Keystone + SQLite in a Next.js app @@ -323,4 +325,15 @@ Embedded mode is a great way to operate a personal Next.js blog or portfolio wit Keystone’s Embedded mode and SQLite support gives you the option to run a self contained CMS from the same place you keep your frontend code. While this option restricts read-write access to people who can run the project in local development, it has advantages with ease of setup, security, and web deployment. This is also a great way to deploy a read-only API on the web for content you manage on your computer. +## Related resources + + + + How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL API playground. + + + export default ({ children }) => {children}; diff --git a/docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.mdx b/docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.mdx index 28005d1e5c8..07efdebe3e7 100644 --- a/docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.mdx +++ b/docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.mdx @@ -1,4 +1,7 @@ import { Markdown } from '../../../components/Markdown'; +import { Well } from '../../../components/primitives/Well'; +import { RelatedContent } from '../../../components/RelatedContent'; +import { InlineCode } from '../../../components/primitives/Code'; ![A terminal with the output of create-keystone-app](/assets/walkthroughs/getting-started/cover.svg) @@ -120,4 +123,27 @@ Read more about the cli in our [command line guides](/guides/cli). - Customise Keystone with the [System Configuration API](/apis/config). - Add fields and relationships using [Schema API](/apis/schema). +## Related resources + + + + Keystone’s CLI helps you develop, build, and deploy projects. This guide explains all you need to standup a new backend in the terminal. + + + The API to configure your options used with the list() function. + + + The API to configure all the parts parts of your Keystone system. + + + export default ({ children }) => {children} From 903e5ce7d6251b5b59f3d1faf001f20963247c41 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Wed, 25 Aug 2021 10:01:05 +1000 Subject: [PATCH 28/76] Added 2x testimonials (#6400) --- docs/pages/for-developers.tsx | 19 ++++++++++++++++++- docs/public/assets/benoit-richert.jpg | Bin 0 -> 9566 bytes docs/public/assets/divslingerx.jpg | Bin 0 -> 25015 bytes 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 docs/public/assets/benoit-richert.jpg create mode 100644 docs/public/assets/divslingerx.jpg diff --git a/docs/pages/for-developers.tsx b/docs/pages/for-developers.tsx index 9a8d63884a5..5f2df11ab01 100644 --- a/docs/pages/for-developers.tsx +++ b/docs/pages/for-developers.tsx @@ -463,12 +463,29 @@ export default function ForDevelopers() { gridTemplateRows: 'masonry', // experimental and hopefully supported soon })} > + + How good is Keystone support! The answers are fast, thought through, technical when + needed, and always gentle... Kudos to the Keystone team, thank you very much!{' '} + + + + I love how Keystone’s access control lets me declare every single Create, Read, + Update, and Delete operation at both the model and{' '} + field level. It’s my favorite way of implementing Auth. + Working with Keystone is a very satisfying experience. I wrapped up 50% of my app’s - schema, API and seed data in a day . The dev + schema, API and seed data in a day The dev experience feels too good to be true {' '} + + + @KeystoneJS + {' '} + is almost too good to be open source. I can’t stress enough how awesome the dev + experience is. This is what I wish Wordpress was. + I think I'm in love. Keystone‘s just what I needed: a dashboard & GraphQL API that works like a charm. As a frontend dev with skills in node and elastic search, Keystone diff --git a/docs/public/assets/benoit-richert.jpg b/docs/public/assets/benoit-richert.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8264538c5fc0c583317beee98c994ceeaa8fdf62 GIT binary patch literal 9566 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 Mb7ltn_VGXe+3&0UHUIzs literal 0 HcmV?d00001 From 5d4841d0394bb0721d94356aea0689b10043a2e4 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Thu, 26 Aug 2021 08:19:52 +1000 Subject: [PATCH 29/76] Typo (#6405) --- docs/pages/for-developers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/for-developers.tsx b/docs/pages/for-developers.tsx index 5f2df11ab01..451350aa4b7 100644 --- a/docs/pages/for-developers.tsx +++ b/docs/pages/for-developers.tsx @@ -484,7 +484,7 @@ export default function ForDevelopers() { @KeystoneJS {' '} is almost too good to be open source. I can’t stress enough how awesome the dev - experience is. This is what I wish Wordpress was. + experience is. This is what I wish WordPress was. I think I'm in love. Keystone‘s just what I needed: a dashboard & GraphQL API that From b6c45a9a1b7626134ef1b9fd523e394f80837931 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Thu, 26 Aug 2021 08:26:13 +1000 Subject: [PATCH 30/76] Replaced absolute links with relative (#6406) --- docs/pages/updates/index.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index e10cf09a19b..24ed2082eb6 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -174,10 +174,9 @@ export default function WhatsNew() {

    We’ve made the experience of working with Keystone’s GraphQL API easier to program and - reason about: We've{' '} - written a complete guide to - the improvements we've made, and it includes a{' '} - + reason about: We've written a complete guide to the + improvements we've made, and it includes a{' '} + checklist of the steps you need to take to upgrade your Keystone projects . From f8ba665ea936ad8e1f3b60408a70160402d7f125 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Thu, 26 Aug 2021 09:22:07 +1000 Subject: [PATCH 31/76] Fix broken link (#6407) To copy https://github.com/keystonejs/keystone/pull/6404 for `website_live` branch --- docs/pages/updates/new-graphql-api.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/updates/new-graphql-api.mdx b/docs/pages/updates/new-graphql-api.mdx index bb1b40223af..aac4440fd5c 100644 --- a/docs/pages/updates/new-graphql-api.mdx +++ b/docs/pages/updates/new-graphql-api.mdx @@ -396,7 +396,7 @@ While there are a lot of changes to this API, we've put a lot of effort into mak 3. Update mutation arguments to match the new input types. Make sure you replace `{ id: "..."}` with `{where: { id: "..."} }` in your `update` and `delete` operations. 4. Update relationship inputs to `create` and `update` operations. Ensure you've replaced usage of `{ disconnectAll: true }` with `{ set: [] }` in to-many relationships, and have used `{ disconnect: true }` rather than `{ disconnect: { id: "..."} }` in to-one relationships. -!> Finally, make sure you apply corresponding changes to filters and input arguments when using the [List Items API](docs/apis/list-items). +!> Finally, make sure you apply corresponding changes to filters and input arguments when using the [List Items API](/docs/apis/list-items). --- From 38bd9650d2c9e6d429414862a949b4e1c0759e4a Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Fri, 27 Aug 2021 13:25:08 +1000 Subject: [PATCH 32/76] Add missing 's in docs pages. (#6421) --- docs/pages/docs/index.tsx | 6 +- docs/pages/updates/index.tsx | 109 ++++++++++++++++++++++++++--------- 2 files changed, 87 insertions(+), 28 deletions(-) diff --git a/docs/pages/docs/index.tsx b/docs/pages/docs/index.tsx index b20d962eca3..977fb76e921 100644 --- a/docs/pages/docs/index.tsx +++ b/docs/pages/docs/index.tsx @@ -1,5 +1,6 @@ /** @jsx jsx */ import { jsx } from '@emotion/react'; +import Link from 'next/link'; import { CommunitySlackCTA } from '../../components/docs/CommunitySlackCTA'; import { Examples } from '../../components/docs/ExamplesList'; @@ -40,7 +41,10 @@ export default function Docs() { Watch Jed's Prisma Day talk to learn about what’s driving the development of Keystone 6, and how it delivers a developer experience that combines features, flexibility, and the perfect amount of abstraction to get started fast, and grow as you learn.{' '} - Read the full transcript. + + Read the full transcript + + .
    diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index 24ed2082eb6..4a824cc16cc 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -174,11 +174,14 @@ export default function WhatsNew() {

    We’ve made the experience of working with Keystone’s GraphQL API easier to program and - reason about: We've written a complete guide to the - improvements we've made, and it includes a{' '} - - checklist of the steps you need to take to upgrade your Keystone projects - + reason about: We've{' '} + + written a complete guide + {' '} + to the improvements we've made, and it includes a{' '} + + checklist of the steps you need to take to upgrade your Keystone projects + .

    @@ -189,15 +192,25 @@ export default function WhatsNew() { We're opening Admin UI up to support a more personal content experience. Now you can: To deliver a more productive editor experience that's aligned with the needs and brand of @@ -243,13 +256,23 @@ export default function WhatsNew() { Next.js and Tailwind, that gives you: Editors can embed audience Polls in post content, and authenticated visitors can make @@ -267,7 +290,11 @@ export default function WhatsNew() { Jed's talk at Prisma Day 2021 is a great overview into what makes Keystone special. Watch - below, or read the full transcript. + below, or{' '} + + read the full transcript + + .
    We've launched our new website for Keystone 6! There’s a new home page, - and background on why Keystone is built for projects that need - to scale on their own terms. Navigating the docs is easier with breadcrumbs, index pages - for Walkthroughs, Guides, and{' '} - APIs, and a better mobile experience. We hope you like it ❤️ + and background on{' '} + + why Keystone + {' '} + is built for projects that need to scale on their own terms. Navigating the docs is easier + with breadcrumbs, index pages for{' '} + + Walkthroughs + + ,{' '} + + Guides + + , and{' '} + + APIs + + , and a better mobile experience. We hope you like it ❤️ @@ -308,19 +349,29 @@ export default function WhatsNew() { written the following guides: @@ -342,11 +393,15 @@ export default function WhatsNew() { A long awaited feature: you can now find an item by unique fields in your schema. It works for{' '} - text + + text + {' '} and{' '} - integer + + integer + {' '} fields that have isUnique: true set. @@ -388,9 +443,9 @@ export default function WhatsNew() { You can now use SQLite to store data via Prisma. It includes support for the{' '} file and cloudinary field types, and lets you{' '} - - embed Keystone inside a Next.js frontend app - + + embed Keystone inside a Next.js frontend app + . From 776da00fff80742ae8f4101af7ae7eeea6314f44 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Fri, 27 Aug 2021 17:36:15 +1000 Subject: [PATCH 33/76] Add `Edit on GitHub` button to all docs pages (#6423) * Progress commit. * Update EditButton.tsx * Update EditButton.tsx --- docs/components/Page.tsx | 17 +++++++- docs/components/primitives/Button.tsx | 6 +++ docs/components/primitives/EditButton.tsx | 47 +++++++++++++++++++++++ docs/pages/docs/apis/index.tsx | 1 + docs/pages/docs/examples.tsx | 1 + docs/pages/docs/guides/index.tsx | 1 + docs/pages/docs/index.tsx | 1 + docs/pages/docs/walkthroughs/index.tsx | 1 + docs/pages/updates/index.tsx | 1 + 9 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/components/primitives/EditButton.tsx diff --git a/docs/components/Page.tsx b/docs/components/Page.tsx index b0fe1ae53b8..6f01f78ed78 100644 --- a/docs/components/Page.tsx +++ b/docs/components/Page.tsx @@ -10,8 +10,10 @@ import type { Heading } from '../lib/getHeadings'; import { Announce } from '../components/Announce'; import { TableOfContents } from './docs/TableOfContents'; import { Wrapper } from './primitives/Wrapper'; +import { EditButton } from './primitives/EditButton'; import { Breadcrumbs } from './Breadcrumbs'; import { Sidebar } from './docs/Sidebar'; +import { Stack } from './primitives/Stack'; import { Header } from './Header'; import { Footer } from './Footer'; @@ -66,6 +68,8 @@ export function DocsPage({ title, description, ogImage, + isIndexPage, + editPath, }: { children: ReactNode; headings?: Heading[]; @@ -75,6 +79,8 @@ export function DocsPage({ title: string; description: string; ogImage?: string; + isIndexPage?: boolean; + editPath?: string; }) { const contentRef = useRef(null); const mq = useMediaQuery(); @@ -119,7 +125,16 @@ export function DocsPage({ ref={contentRef} className={noProse ? '' : 'prose'} > - + + + {!isUpdatesPage && ( + + )} + {children} {!!headings.length && !noRightNav && ( diff --git a/docs/components/primitives/Button.tsx b/docs/components/primitives/Button.tsx index 4261a937b9e..39f224c6caf 100644 --- a/docs/components/primitives/Button.tsx +++ b/docs/components/primitives/Button.tsx @@ -94,6 +94,12 @@ const sizeMap = { height: '2.2rem', padding: '0 14px', }, + xsmall: { + fontSize: '.75rem', + borderRadius: '4px', + height: '2rem', + padding: '0 12px', + }, }; type ButtonProps = { diff --git a/docs/components/primitives/EditButton.tsx b/docs/components/primitives/EditButton.tsx new file mode 100644 index 00000000000..4db732d9fd0 --- /dev/null +++ b/docs/components/primitives/EditButton.tsx @@ -0,0 +1,47 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/react'; + +import { Edit } from '../../components/icons/Edit'; +import { Button } from './Button'; + +export function EditButton({ + pathName, + isIndexPage, + editPath, +}: { + pathName: string; + isIndexPage?: boolean; + editPath?: string; +}) { + let fileUrl = `https://github.com/keystonejs/keystone/edit/website_live/docs/pages/`; + + if (editPath) { + fileUrl += editPath; + } else if (isIndexPage) { + fileUrl += `${pathName}/index.tsx`; + } else { + fileUrl += `${pathName}.mdx`; + } + + return ( + + ); +} diff --git a/docs/pages/docs/apis/index.tsx b/docs/pages/docs/apis/index.tsx index c77f14c2ba0..a390f1e5ec7 100644 --- a/docs/pages/docs/apis/index.tsx +++ b/docs/pages/docs/apis/index.tsx @@ -16,6 +16,7 @@ export default function Docs() { noProse title={'APIs'} description={'Index for Keystone’s API reference docs.'} + isIndexPage > API Reference diff --git a/docs/pages/docs/examples.tsx b/docs/pages/docs/examples.tsx index f11f3e16562..b74b068fc9a 100644 --- a/docs/pages/docs/examples.tsx +++ b/docs/pages/docs/examples.tsx @@ -15,6 +15,7 @@ export default function Docs() { description={ 'A growing collection of projects you can run locally to learn more about Keystone’s many features. Use them as a reference for best practice, and springboard when adding features to your own project.' } + editPath={'docs/examples.tsx'} > Examples diff --git a/docs/pages/docs/guides/index.tsx b/docs/pages/docs/guides/index.tsx index 2da2b2dc68d..826749e0580 100644 --- a/docs/pages/docs/guides/index.tsx +++ b/docs/pages/docs/guides/index.tsx @@ -18,6 +18,7 @@ export default function Docs() { description={ 'Practical explanations of Keystone’s fundamental building blocks. Learn how to think about, and get the most out of Keystone’s many features.' } + isIndexPage > Keystone Guides diff --git a/docs/pages/docs/index.tsx b/docs/pages/docs/index.tsx index 977fb76e921..39194cd9177 100644 --- a/docs/pages/docs/index.tsx +++ b/docs/pages/docs/index.tsx @@ -19,6 +19,7 @@ export default function Docs() { noProse title={'Keystone Docs Home'} description={'Developer docs for KeystoneJS: The superpowered headless CMS for developers.'} + isIndexPage > Keystone Docs diff --git a/docs/pages/docs/walkthroughs/index.tsx b/docs/pages/docs/walkthroughs/index.tsx index 05c827c2c2c..c6a5e3bd8be 100644 --- a/docs/pages/docs/walkthroughs/index.tsx +++ b/docs/pages/docs/walkthroughs/index.tsx @@ -14,6 +14,7 @@ export default function Docs() { description={ 'Explore tutorials with step-by-step instruction on building solutions with Keystone.' } + isIndexPage > Walkthroughs diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index 4a824cc16cc..36b3be48ca4 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -129,6 +129,7 @@ export default function WhatsNew() { noProse title={'Latest News'} description={'What’s new with Keystone. A snapshot of announcements and recent releases.'} + isIndexPage > Latest News From 9b02e0d2d157cd8cc2926d639ac01085f570a7df Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Mon, 30 Aug 2021 10:34:39 +1000 Subject: [PATCH 34/76] Tab index improvements. (#6427) --- docs/components/Header.tsx | 53 +++++++++++++++++++++++++---- docs/components/docs/Navigation.tsx | 23 +++++++++---- docs/package.json | 2 ++ yarn.lock | 9 ++++- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/docs/components/Header.tsx b/docs/components/Header.tsx index 23839cc99d7..fd626a47d71 100644 --- a/docs/components/Header.tsx +++ b/docs/components/Header.tsx @@ -1,12 +1,20 @@ /** @jsx jsx */ -import { createContext, useContext, useEffect, useState, useRef, ReactNode } from 'react'; +import { + createContext, + useContext, + useCallback, + useEffect, + useState, + useRef, + ReactNode, +} from 'react'; import { useRouter } from 'next/router'; import { jsx } from '@emotion/react'; import Link from 'next/link'; +import debounce from 'lodash.debounce'; -import { useCallback } from 'react'; +import { BREAK_POINTS } from '../lib/media'; import { useMediaQuery } from '../lib/media'; - import { SearchField } from './primitives/SearchField'; import { Highlight } from './primitives/Highlight'; import { Wrapper } from './primitives/Wrapper'; @@ -20,8 +28,11 @@ import { GitHub } from './icons/GitHub'; // TODO: Add in search for mobile via this button // import { Search } from './icons/Search'; -type HeaderContextType = { mobileNavIsOpen: boolean }; -const HeaderContext = createContext({ mobileNavIsOpen: false }); +type HeaderContextType = { mobileNavIsOpen: boolean; desktopOpenState: number }; +const HeaderContext = createContext({ + mobileNavIsOpen: false, + desktopOpenState: -1, +}); export const useHeaderContext = () => useContext(HeaderContext); function Logo() { @@ -94,6 +105,7 @@ function LinkItem({ children, href }: { children: ReactNode; href: string }) { (null); const headerRef = useRef(null); + const [mobileNavIsOpen, setMobileNavIsOpen] = useState(false); + const [desktopOpenState, setDesktopOpenState] = useState(-1); + + useEffect(() => { + const listener = () => { + setMobileNavIsOpen(false); + setDesktopOpenState(-1); + const width = Math.max( + document.body.scrollWidth, + document.documentElement.scrollWidth, + document.body.offsetWidth, + document.documentElement.offsetWidth, + document.documentElement.clientWidth + ); + if (width > BREAK_POINTS.sm) { + setDesktopOpenState(-1); + } else { + setDesktopOpenState(-1); + } + }; + window.addEventListener('resize', debounce(listener, 130)); + + return () => { + window.removeEventListener('resize', debounce(listener, 130)); + }; + }, [setDesktopOpenState]); + useEffect(() => { document.body.style.overflow = 'auto'; // search - init field @@ -270,7 +309,7 @@ export function Header() { > - +
    ; -export function NavItem({ href, isActive: _isActive, isPlaceholder, ...props }: NavItemProps) { +export function NavItem({ + href, + isActive: _isActive, + isPlaceholder, + alwaysVisible, + ...props +}: NavItemProps) { const { pathname } = useRouter(); const mq = useMediaQuery(); - let isActive = _isActive || pathname === href; + const isActive = _isActive || pathname === href; const ctx = useHeaderContext(); - const isOpen = ctx ? ctx.mobileNavIsOpen : true; + const isMobileNavOpen = ctx ? ctx.mobileNavIsOpen : true; + const desktopOpenState = ctx ? ctx.desktopOpenState : -1; return ( Date: Mon, 30 Aug 2021 12:39:10 +1000 Subject: [PATCH 35/76] Update EditButton.tsx (#6428) --- docs/components/primitives/EditButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/components/primitives/EditButton.tsx b/docs/components/primitives/EditButton.tsx index 4db732d9fd0..7295cfe9eee 100644 --- a/docs/components/primitives/EditButton.tsx +++ b/docs/components/primitives/EditButton.tsx @@ -13,10 +13,10 @@ export function EditButton({ isIndexPage?: boolean; editPath?: string; }) { - let fileUrl = `https://github.com/keystonejs/keystone/edit/website_live/docs/pages/`; + let fileUrl = `https://github.com/keystonejs/keystone/edit/website_live/docs/pages`; if (editPath) { - fileUrl += editPath; + fileUrl += `/${editPath}`; } else if (isIndexPage) { fileUrl += `${pathName}/index.tsx`; } else { From dd357d08670b5416d9910febc3b979a4a7e239ce Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Thu, 2 Sep 2021 11:01:57 +1000 Subject: [PATCH 36/76] Fix styles on document field demo on website live (#6447) --- docs/pages/docs/guides/document-field-demo.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/docs/guides/document-field-demo.mdx b/docs/pages/docs/guides/document-field-demo.mdx index d80abb27b26..36e3f76e9bd 100644 --- a/docs/pages/docs/guides/document-field-demo.mdx +++ b/docs/pages/docs/guides/document-field-demo.mdx @@ -25,6 +25,7 @@ export default ({ children }) => { const headings = getHeadings(children); return ( Date: Thu, 2 Sep 2021 11:55:04 +1000 Subject: [PATCH 37/76] Content edits (#6451) --- docs/pages/docs/guides/document-field-demo.mdx | 5 ----- docs/pages/docs/guides/document-fields.mdx | 9 +++++---- .../chomeless-example-docs-demo.png | Bin 0 -> 166335 bytes 3 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 docs/public/assets/guides/document-fields/chomeless-example-docs-demo.png diff --git a/docs/pages/docs/guides/document-field-demo.mdx b/docs/pages/docs/guides/document-field-demo.mdx index 36e3f76e9bd..4a23ab743e2 100644 --- a/docs/pages/docs/guides/document-field-demo.mdx +++ b/docs/pages/docs/guides/document-field-demo.mdx @@ -34,11 +34,6 @@ export default ({ children }) => { id: 'document-field-demo', depth: 1, }, - { - label: 'Try the demo', - id: 'try-the-demo', - depth: 2, - }, ...headings, ]} > diff --git a/docs/pages/docs/guides/document-fields.mdx b/docs/pages/docs/guides/document-fields.mdx index fcfe22e204d..664a7f01ae6 100644 --- a/docs/pages/docs/guides/document-fields.mdx +++ b/docs/pages/docs/guides/document-fields.mdx @@ -375,7 +375,7 @@ export default config({
    - In the document editor at the top of this page, the Quote(shown above), Notice and Hero are + In the [document editor demo](/docs/guides/document-field-demo), the insertable Quote, Notice and Hero items are implemented as component blocks, see the implementation for Notice and Hero by expanding this. @@ -641,9 +641,10 @@ fields.conditional(fields.checkbox({ label: 'Show Call to action' }), { ### Chromeless -If you want to give your component blocks a more native feel in the editor, you can set `chromeless: true`. -When you disable it, the generated form is disabled. -In the editor at the top of this page, the Notice and Quote blocks are chromeless and the Hero has the chrome enabled. +If you want to give your component blocks a more native feel in the editor, you can set `chromeless: true` to disable Keystone's standard generated edit form. In the [document editor demo](/docs/guides/document-field-demo), the Notice and Quote blocks are chromeless, but the Hero block has the standard chrome styling: + +![Notice, Quote, and Hero component blocks demonstrating chrome, and chromeless styling](/assets/guides/document-fields/chomeless-example-docs-demo.png) + You will likely want to provide a custom [toolbar](#toolbar) when you set `chromeless: true`. ```tsx diff --git a/docs/public/assets/guides/document-fields/chomeless-example-docs-demo.png b/docs/public/assets/guides/document-fields/chomeless-example-docs-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..e1470ec92f29ed30127a6759510b8c9b8858bcda GIT binary patch literal 166335 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

    %4Dfpz#L}ICo2x9Psx8!3Ypja^QO;s`|akEsC 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

    + ) : null )} diff --git a/design-system/packages/core/src/components/Link.tsx b/design-system/packages/core/src/components/Link.tsx index 4d864ff6e37..0f7b5e22b44 100644 --- a/design-system/packages/core/src/components/Link.tsx +++ b/design-system/packages/core/src/components/Link.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '../emotion'; diff --git a/design-system/packages/core/src/components/Stack.tsx b/design-system/packages/core/src/components/Stack.tsx index 03d4c2abd15..ae06186d42a 100644 --- a/design-system/packages/core/src/components/Stack.tsx +++ b/design-system/packages/core/src/components/Stack.tsx @@ -1,12 +1,13 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ -import { ElementType, Children, Fragment, ReactNode, isValidElement } from 'react'; +import { Children, Fragment, ReactNode, isValidElement } from 'react'; import { jsx } from '../emotion'; import { useMediaQuery } from '../hooks/useMediaQuery'; import { useTheme } from '../theme'; import { Theme } from '../types'; -import { forwardRefWithAs, mapResponsiveProp } from '../utils'; +import { forwardRefWithAs, mapResponsiveProp, getChildTag } from '../utils'; import { Box, BoxProps } from './Box'; import { Divider } from './Divider'; @@ -44,16 +45,6 @@ export type StackProps = { gap?: keyof Theme['spacing']; } & BoxProps; -const getChildTag = (parentTag?: ElementType) => { - switch (parentTag) { - case 'ul': - case 'ol': - return 'li'; - default: - return 'div'; - } -}; - export const Stack = forwardRefWithAs<'div', StackProps>( ({ across, align = 'stretch', children, dividers = 'none', gap = 'none', ...props }, ref) => { const { spacing } = useTheme(); diff --git a/design-system/packages/core/src/components/Text.tsx b/design-system/packages/core/src/components/Text.tsx index 8ec418df1e1..58eeb9bf126 100644 --- a/design-system/packages/core/src/components/Text.tsx +++ b/design-system/packages/core/src/components/Text.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '../emotion'; diff --git a/design-system/packages/core/src/utils.ts b/design-system/packages/core/src/utils.ts index 0841bfc38be..0a41678c6c6 100644 --- a/design-system/packages/core/src/utils.ts +++ b/design-system/packages/core/src/utils.ts @@ -11,6 +11,20 @@ import { } from 'react'; import { createPortal } from 'react-dom'; +/* + Simple switch to return a child tag from a parent tag argument. + Returns a div by default. +*/ +export const getChildTag = (parentTag?: ElementType) => { + switch (parentTag) { + case 'ul': + case 'ol': + return 'li'; + default: + return 'div'; + } +}; + /* @johannes' one weird trick for fixing TypeScript autocomplete */ diff --git a/design-system/packages/fields/CHANGELOG.md b/design-system/packages/fields/CHANGELOG.md index 14e27b236b6..47abec7b693 100644 --- a/design-system/packages/fields/CHANGELOG.md +++ b/design-system/packages/fields/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-ui/fields +## 4.1.3 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + - @keystone-ui/icons@4.0.1 + - @keystone-ui/popover@4.0.3 + ## 4.1.2 ### Patch Changes diff --git a/design-system/packages/fields/package.json b/design-system/packages/fields/package.json index a82ec123dc0..e352f8837b5 100644 --- a/design-system/packages/fields/package.json +++ b/design-system/packages/fields/package.json @@ -1,17 +1,17 @@ { "name": "@keystone-ui/fields", - "version": "4.1.2", + "version": "4.1.3", "license": "MIT", "main": "dist/fields.cjs.js", "module": "dist/fields.esm.js", "devDependencies": { - "@types/react": "^17.0.18" + "@types/react": "^17.0.19" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.1.0", - "@keystone-ui/icons": "^4.0.0", - "@keystone-ui/popover": "^4.0.2", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/icons": "^4.0.1", + "@keystone-ui/popover": "^4.0.3", "@types/react-select": "^4.0.17", "date-fns": "^2.23.0", "react": "^17.0.2", diff --git a/design-system/packages/fields/src/Checkbox.tsx b/design-system/packages/fields/src/Checkbox.tsx index 517a60c6f19..9a0625c90e0 100644 --- a/design-system/packages/fields/src/Checkbox.tsx +++ b/design-system/packages/fields/src/Checkbox.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, InputHTMLAttributes, ReactNode, forwardRef } from 'react'; diff --git a/design-system/packages/fields/src/DatePicker/Calendar.tsx b/design-system/packages/fields/src/DatePicker/Calendar.tsx index 4dd6fac6adb..9158708fd30 100644 --- a/design-system/packages/fields/src/DatePicker/Calendar.tsx +++ b/design-system/packages/fields/src/DatePicker/Calendar.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useMemo } from 'react'; diff --git a/design-system/packages/fields/src/DatePicker/components/Adornments.tsx b/design-system/packages/fields/src/DatePicker/components/Adornments.tsx index 771b3220433..ae90d451375 100644 --- a/design-system/packages/fields/src/DatePicker/components/Adornments.tsx +++ b/design-system/packages/fields/src/DatePicker/components/Adornments.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ElementType, ReactNode, createContext, useContext } from 'react'; diff --git a/design-system/packages/fields/src/DatePicker/components/InputButton.tsx b/design-system/packages/fields/src/DatePicker/components/InputButton.tsx index 23abe06742f..b185cc6dfca 100644 --- a/design-system/packages/fields/src/DatePicker/components/InputButton.tsx +++ b/design-system/packages/fields/src/DatePicker/components/InputButton.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ButtonHTMLAttributes, forwardRef } from 'react'; diff --git a/design-system/packages/fields/src/DatePicker/index.tsx b/design-system/packages/fields/src/DatePicker/index.tsx index c18f038a299..fcec34d452c 100644 --- a/design-system/packages/fields/src/DatePicker/index.tsx +++ b/design-system/packages/fields/src/DatePicker/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import React, { Fragment, useCallback } from 'react'; diff --git a/design-system/packages/fields/src/FieldContainer.tsx b/design-system/packages/fields/src/FieldContainer.tsx index 28cf6c7e7e4..1341139129c 100644 --- a/design-system/packages/fields/src/FieldContainer.tsx +++ b/design-system/packages/fields/src/FieldContainer.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, forwardRefWithAs } from '@keystone-ui/core'; export const FieldContainer = forwardRefWithAs<'div', {}>(({ as: Tag = 'div', ...props }, ref) => { diff --git a/design-system/packages/fields/src/FieldLabel.tsx b/design-system/packages/fields/src/FieldLabel.tsx index b3fef290f22..32a6a78b230 100644 --- a/design-system/packages/fields/src/FieldLabel.tsx +++ b/design-system/packages/fields/src/FieldLabel.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { forwardRefWithAs, jsx, useTheme } from '@keystone-ui/core'; import type { ReactNode } from 'react'; diff --git a/design-system/packages/fields/src/FieldLegend.tsx b/design-system/packages/fields/src/FieldLegend.tsx index 7008a3698b5..3c8fd7d5a71 100644 --- a/design-system/packages/fields/src/FieldLegend.tsx +++ b/design-system/packages/fields/src/FieldLegend.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; import type { HTMLAttributes } from 'react'; diff --git a/design-system/packages/fields/src/Radio.tsx b/design-system/packages/fields/src/Radio.tsx index dfd55101bc2..ec953acc128 100644 --- a/design-system/packages/fields/src/Radio.tsx +++ b/design-system/packages/fields/src/Radio.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, InputHTMLAttributes, ReactNode, forwardRef } from 'react'; diff --git a/design-system/packages/fields/src/Select.tsx b/design-system/packages/fields/src/Select.tsx index c476db54520..7b0ef7bcc91 100644 --- a/design-system/packages/fields/src/Select.tsx +++ b/design-system/packages/fields/src/Select.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; import ReactSelect, { OptionsType, mergeStyles, NamedProps } from 'react-select'; diff --git a/design-system/packages/fields/src/Switch.tsx b/design-system/packages/fields/src/Switch.tsx index d61319e3f13..e10a1f20eb1 100644 --- a/design-system/packages/fields/src/Switch.tsx +++ b/design-system/packages/fields/src/Switch.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ /** diff --git a/design-system/packages/fields/src/TextArea.tsx b/design-system/packages/fields/src/TextArea.tsx index 5addf9ec851..a4b6fd6e504 100644 --- a/design-system/packages/fields/src/TextArea.tsx +++ b/design-system/packages/fields/src/TextArea.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { InputHTMLAttributes, forwardRef } from 'react'; import { jsx } from '@keystone-ui/core'; diff --git a/design-system/packages/fields/src/TextInput.tsx b/design-system/packages/fields/src/TextInput.tsx index 08e66e4ce90..786f89c257d 100644 --- a/design-system/packages/fields/src/TextInput.tsx +++ b/design-system/packages/fields/src/TextInput.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ /** * TODO diff --git a/design-system/packages/fields/src/components/ControlLabel.tsx b/design-system/packages/fields/src/components/ControlLabel.tsx index 9e7f9c4b725..93df27c2ac2 100644 --- a/design-system/packages/fields/src/components/ControlLabel.tsx +++ b/design-system/packages/fields/src/components/ControlLabel.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ReactNode, ReactElement } from 'react'; diff --git a/design-system/packages/fields/src/components/Icons.tsx b/design-system/packages/fields/src/components/Icons.tsx index f1505813272..7f64e487b70 100644 --- a/design-system/packages/fields/src/components/Icons.tsx +++ b/design-system/packages/fields/src/components/Icons.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ReactNode } from 'react'; diff --git a/design-system/packages/icons/CHANGELOG.md b/design-system/packages/icons/CHANGELOG.md index 1e048c80092..8262cf15e40 100644 --- a/design-system/packages/icons/CHANGELOG.md +++ b/design-system/packages/icons/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-ui/icons +## 4.0.1 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + ## 4.0.0 ### Major Changes diff --git a/design-system/packages/icons/package.json b/design-system/packages/icons/package.json index 7a3c11a6eb2..bff4e912da2 100644 --- a/design-system/packages/icons/package.json +++ b/design-system/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-ui/icons", - "version": "4.0.0", + "version": "4.0.1", "license": "MIT", "main": "dist/icons.cjs.js", "module": "dist/icons.esm.js", @@ -12,7 +12,7 @@ "@svgr/plugin-jsx": "^5.5.0", "@svgr/plugin-prettier": "^5.5.0", "@svgr/plugin-svgo": "^5.5.0", - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "chalk": "^4.1.2", "feather-icons": "^4.28.0", "fs-extra": "^10.0.0", @@ -22,7 +22,7 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0" + "@keystone-ui/core": "^3.2.0" }, "peerDependencies": { "react": "^17.0.2" diff --git a/design-system/packages/icons/src/Icon.tsx b/design-system/packages/icons/src/Icon.tsx index 08543dd8ead..b12d30d8358 100644 --- a/design-system/packages/icons/src/Icon.tsx +++ b/design-system/packages/icons/src/Icon.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { SVGAttributes, forwardRef, ReactNode } from 'react'; diff --git a/design-system/packages/loading/CHANGELOG.md b/design-system/packages/loading/CHANGELOG.md index 532ed42145f..e17f55e7f20 100644 --- a/design-system/packages/loading/CHANGELOG.md +++ b/design-system/packages/loading/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-ui/loading +## 4.0.1 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + ## 4.0.0 ### Major Changes diff --git a/design-system/packages/loading/package.json b/design-system/packages/loading/package.json index 98a7c74bebc..612e6a53a9b 100644 --- a/design-system/packages/loading/package.json +++ b/design-system/packages/loading/package.json @@ -1,15 +1,15 @@ { "name": "@keystone-ui/loading", - "version": "4.0.0", + "version": "4.0.1", "license": "MIT", "main": "dist/loading.cjs.js", "module": "dist/loading.esm.js", "devDependencies": { - "@types/react": "^17.0.18" + "@types/react": "^17.0.19" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", + "@keystone-ui/core": "^3.2.0", "react": "^17.0.2" }, "engines": { diff --git a/design-system/packages/loading/src/Loading.tsx b/design-system/packages/loading/src/Loading.tsx index b9e7daaab98..7a3105312e9 100644 --- a/design-system/packages/loading/src/Loading.tsx +++ b/design-system/packages/loading/src/Loading.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, keyframes, useTheme } from '@keystone-ui/core'; diff --git a/design-system/packages/modals/CHANGELOG.md b/design-system/packages/modals/CHANGELOG.md index 87e991cc96b..47d0e0cacfa 100644 --- a/design-system/packages/modals/CHANGELOG.md +++ b/design-system/packages/modals/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-ui/modals +## 4.0.1 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + ## 4.0.0 ### Major Changes diff --git a/design-system/packages/modals/package.json b/design-system/packages/modals/package.json index 43f4ad1d17c..27c6927dd15 100644 --- a/design-system/packages/modals/package.json +++ b/design-system/packages/modals/package.json @@ -1,16 +1,16 @@ { "name": "@keystone-ui/modals", - "version": "4.0.0", + "version": "4.0.1", "license": "MIT", "main": "dist/modals.cjs.js", "module": "dist/modals.esm.js", "devDependencies": { - "@types/react": "^17.0.18" + "@types/react": "^17.0.19" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.0.0", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", "react": "^17.0.2", "react-focus-lock": "^2.5.2", "react-remove-scroll": "^2.4.3", diff --git a/design-system/packages/modals/src/AlertDialog.tsx b/design-system/packages/modals/src/AlertDialog.tsx index 888711701b7..24b702336c0 100644 --- a/design-system/packages/modals/src/AlertDialog.tsx +++ b/design-system/packages/modals/src/AlertDialog.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Button } from '@keystone-ui/button'; diff --git a/design-system/packages/modals/src/Blanket.tsx b/design-system/packages/modals/src/Blanket.tsx index 747390c2216..26f69e15739 100644 --- a/design-system/packages/modals/src/Blanket.tsx +++ b/design-system/packages/modals/src/Blanket.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { HTMLAttributes, forwardRef } from 'react'; diff --git a/design-system/packages/modals/src/DialogBase.tsx b/design-system/packages/modals/src/DialogBase.tsx index f14dc2df459..43af8e59f0c 100644 --- a/design-system/packages/modals/src/DialogBase.tsx +++ b/design-system/packages/modals/src/DialogBase.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, KeyboardEvent, ReactNode } from 'react'; diff --git a/design-system/packages/modals/src/Drawer.tsx b/design-system/packages/modals/src/Drawer.tsx index 05a49e97b76..cf67f15cd5c 100644 --- a/design-system/packages/modals/src/Drawer.tsx +++ b/design-system/packages/modals/src/Drawer.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { MutableRefObject, ReactNode } from 'react'; diff --git a/design-system/packages/modals/src/DrawerBase.tsx b/design-system/packages/modals/src/DrawerBase.tsx index 5462ddcc9ee..2c27c6d2359 100644 --- a/design-system/packages/modals/src/DrawerBase.tsx +++ b/design-system/packages/modals/src/DrawerBase.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, KeyboardEvent, MutableRefObject, ReactNode, useCallback, useRef } from 'react'; diff --git a/design-system/packages/notice/CHANGELOG.md b/design-system/packages/notice/CHANGELOG.md index 9f450557c56..47173ea8ba4 100644 --- a/design-system/packages/notice/CHANGELOG.md +++ b/design-system/packages/notice/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-ui/notice +## 4.0.2 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/icons@4.0.1 + ## 4.0.1 ### Patch Changes diff --git a/design-system/packages/notice/package.json b/design-system/packages/notice/package.json index 77428a5a921..59dd9d1e6fc 100644 --- a/design-system/packages/notice/package.json +++ b/design-system/packages/notice/package.json @@ -1,17 +1,17 @@ { "name": "@keystone-ui/notice", - "version": "4.0.1", + "version": "4.0.2", "license": "MIT", "main": "dist/notice.cjs.js", "module": "dist/notice.esm.js", "devDependencies": { - "@types/react": "^17.0.18" + "@types/react": "^17.0.19" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/icons": "^4.0.0", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/icons": "^4.0.1", "react": "^17.0.2" }, "engines": { diff --git a/design-system/packages/notice/src/Notice.tsx b/design-system/packages/notice/src/Notice.tsx index d94df6b9414..e9ddfa27121 100644 --- a/design-system/packages/notice/src/Notice.tsx +++ b/design-system/packages/notice/src/Notice.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ReactNode, useMemo } from 'react'; diff --git a/design-system/packages/notice/src/hooks/button.ts b/design-system/packages/notice/src/hooks/button.ts index 421427c7cf7..9f7841a25ca 100644 --- a/design-system/packages/notice/src/hooks/button.ts +++ b/design-system/packages/notice/src/hooks/button.ts @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useTheme } from '@keystone-ui/core'; diff --git a/design-system/packages/options/CHANGELOG.md b/design-system/packages/options/CHANGELOG.md index 793a4ad767b..555d8e07455 100644 --- a/design-system/packages/options/CHANGELOG.md +++ b/design-system/packages/options/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-ui/options +## 4.0.2 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/icons@4.0.1 + ## 4.0.1 ### Patch Changes diff --git a/design-system/packages/options/package.json b/design-system/packages/options/package.json index 2a16ea71b94..bda29369afb 100644 --- a/design-system/packages/options/package.json +++ b/design-system/packages/options/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-ui/options", - "version": "4.0.1", + "version": "4.0.2", "license": "MIT", "main": "dist/options.cjs.js", "module": "dist/options.esm.js", @@ -12,9 +12,9 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/fields": "^4.1.2", - "@keystone-ui/icons": "^4.0.0", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/icons": "^4.0.1", "@types/react-select": "^4.0.17", "react-select": "^4.3.1" }, diff --git a/design-system/packages/options/src/index.tsx b/design-system/packages/options/src/index.tsx index ea5bb4accc9..68b051c8b8b 100644 --- a/design-system/packages/options/src/index.tsx +++ b/design-system/packages/options/src/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; import { useIndicatorTokens } from '@keystone-ui/fields'; diff --git a/design-system/packages/pill/CHANGELOG.md b/design-system/packages/pill/CHANGELOG.md index 874d3e23610..f5adcd956f0 100644 --- a/design-system/packages/pill/CHANGELOG.md +++ b/design-system/packages/pill/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-ui/pill +## 5.0.1 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + - @keystone-ui/icons@4.0.1 + ## 5.0.0 ### Major Changes diff --git a/design-system/packages/pill/package.json b/design-system/packages/pill/package.json index 7687bdb2767..e2d6f24cf83 100644 --- a/design-system/packages/pill/package.json +++ b/design-system/packages/pill/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-ui/pill", - "version": "5.0.0", + "version": "5.0.1", "license": "MIT", "main": "dist/pill.cjs.js", "module": "dist/pill.esm.js", @@ -12,8 +12,8 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/icons": "^4.0.0" + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/icons": "^4.0.1" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/design-system/packages/pill/src/index.tsx b/design-system/packages/pill/src/index.tsx index fc8b3a5559a..547b132bfe2 100644 --- a/design-system/packages/pill/src/index.tsx +++ b/design-system/packages/pill/src/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; import { ButtonHTMLAttributes, HTMLAttributes, forwardRef, ReactNode } from 'react'; diff --git a/design-system/packages/popover/CHANGELOG.md b/design-system/packages/popover/CHANGELOG.md index 8a82ea7509e..f62e8263b8e 100644 --- a/design-system/packages/popover/CHANGELOG.md +++ b/design-system/packages/popover/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-ui/popover +## 4.0.3 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + ## 4.0.2 ### Patch Changes diff --git a/design-system/packages/popover/package.json b/design-system/packages/popover/package.json index 52762002475..f10bdae1bbe 100644 --- a/design-system/packages/popover/package.json +++ b/design-system/packages/popover/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-ui/popover", - "version": "4.0.2", + "version": "4.0.3", "license": "MIT", "main": "dist/popover.cjs.js", "module": "dist/popover.esm.js", @@ -14,7 +14,7 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", + "@keystone-ui/core": "^3.2.0", "@popperjs/core": "^2.9.3", "focus-trap": "^6.6.1", "react-popper": "^2.2.5" diff --git a/design-system/packages/popover/src/Popover.tsx b/design-system/packages/popover/src/Popover.tsx index 35178bf6570..56b26e21c7d 100644 --- a/design-system/packages/popover/src/Popover.tsx +++ b/design-system/packages/popover/src/Popover.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { diff --git a/design-system/packages/segmented-control/CHANGELOG.md b/design-system/packages/segmented-control/CHANGELOG.md index 537191bf60f..d273264335c 100644 --- a/design-system/packages/segmented-control/CHANGELOG.md +++ b/design-system/packages/segmented-control/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-ui/segmented-control +## 4.0.3 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + ## 4.0.2 ### Patch Changes diff --git a/design-system/packages/segmented-control/package.json b/design-system/packages/segmented-control/package.json index 51d0acd8fdd..5d8dd288add 100644 --- a/design-system/packages/segmented-control/package.json +++ b/design-system/packages/segmented-control/package.json @@ -1,16 +1,16 @@ { "name": "@keystone-ui/segmented-control", - "version": "4.0.2", + "version": "4.0.3", "license": "MIT", "main": "dist/segmented-control.cjs.js", "module": "dist/segmented-control.esm.js", "devDependencies": { - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "react": "^17.0.2" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.1.0" + "@keystone-ui/core": "^3.2.0" }, "peerDependencies": { "react": "^17.0.2" diff --git a/design-system/packages/segmented-control/src/SegmentedControl.tsx b/design-system/packages/segmented-control/src/SegmentedControl.tsx index d47a66f5976..57d07033845 100644 --- a/design-system/packages/segmented-control/src/SegmentedControl.tsx +++ b/design-system/packages/segmented-control/src/SegmentedControl.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ /** diff --git a/design-system/packages/toast/CHANGELOG.md b/design-system/packages/toast/CHANGELOG.md index ae0d11b3ad0..39d86ebd9d1 100644 --- a/design-system/packages/toast/CHANGELOG.md +++ b/design-system/packages/toast/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-ui/toast +## 4.0.3 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + - @keystone-ui/icons@4.0.1 + ## 4.0.2 ### Patch Changes diff --git a/design-system/packages/toast/package.json b/design-system/packages/toast/package.json index 3c1ebc4c2df..1471e5d9796 100644 --- a/design-system/packages/toast/package.json +++ b/design-system/packages/toast/package.json @@ -1,17 +1,17 @@ { "name": "@keystone-ui/toast", - "version": "4.0.2", + "version": "4.0.3", "license": "MIT", "main": "dist/toast.cjs.js", "module": "dist/toast.esm.js", "devDependencies": { - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "react": "^17.0.2" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/icons": "^4.0.0" + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/icons": "^4.0.1" }, "peerDependencies": { "react": "^17.0.2" diff --git a/design-system/packages/toast/src/Toast.tsx b/design-system/packages/toast/src/Toast.tsx index f6d538c6ac8..636c41da738 100644 --- a/design-system/packages/toast/src/Toast.tsx +++ b/design-system/packages/toast/src/Toast.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { HTMLAttributes, ReactNode, forwardRef, useEffect, useMemo, useState } from 'react'; diff --git a/design-system/packages/tooltip/CHANGELOG.md b/design-system/packages/tooltip/CHANGELOG.md index 0aacc64d7d5..04b0e19a3fa 100644 --- a/design-system/packages/tooltip/CHANGELOG.md +++ b/design-system/packages/tooltip/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-ui/tooltip +## 4.0.2 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + - @keystone-ui/popover@4.0.3 + ## 4.0.1 ### Patch Changes diff --git a/design-system/packages/tooltip/package.json b/design-system/packages/tooltip/package.json index 57cefc86d4d..a4ab43adcc3 100644 --- a/design-system/packages/tooltip/package.json +++ b/design-system/packages/tooltip/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-ui/tooltip", - "version": "4.0.1", + "version": "4.0.2", "license": "MIT", "main": "dist/tooltip.cjs.js", "module": "dist/tooltip.esm.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/popover": "^4.0.0", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/popover": "^4.0.3", "apply-ref": "^1.0.0" }, "engines": { diff --git a/design-system/packages/tooltip/src/Tooltip.tsx b/design-system/packages/tooltip/src/Tooltip.tsx index 1ad77f33731..0f8e0a5d68e 100644 --- a/design-system/packages/tooltip/src/Tooltip.tsx +++ b/design-system/packages/tooltip/src/Tooltip.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { diff --git a/design-system/website/CHANGELOG.md b/design-system/website/CHANGELOG.md index 2eb4512fee0..122eeb299ac 100644 --- a/design-system/website/CHANGELOG.md +++ b/design-system/website/CHANGELOG.md @@ -1,5 +1,27 @@ # @keystone-ui/website +## 3.0.2 + +### Patch Changes + +- [#6443](https://github.com/keystonejs/keystone/pull/6443) [`b45536e22`](https://github.com/keystonejs/keystone/commit/b45536e22f9c3a61c781161602f6f01268b303c7) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused dependency `@types/webpack`. + +* [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +* Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/loading@4.0.1 + - @keystone-ui/modals@4.0.1 + - @keystone-ui/notice@4.0.2 + - @keystone-ui/options@4.0.2 + - @keystone-ui/pill@5.0.1 + - @keystone-ui/popover@4.0.3 + - @keystone-ui/segmented-control@4.0.3 + - @keystone-ui/toast@4.0.3 + - @keystone-ui/tooltip@4.0.2 + ## 3.0.1 ### Patch Changes diff --git a/design-system/website/components/Code.tsx b/design-system/website/components/Code.tsx index 680d6f0a0e8..3234b348d87 100644 --- a/design-system/website/components/Code.tsx +++ b/design-system/website/components/Code.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { ReactNode } from 'react'; import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/design-system/website/components/Navigation.tsx b/design-system/website/components/Navigation.tsx index a41d3654b72..ee8a6916537 100644 --- a/design-system/website/components/Navigation.tsx +++ b/design-system/website/components/Navigation.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { Fragment, ReactNode } from 'react'; import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/design-system/website/components/Page.tsx b/design-system/website/components/Page.tsx index f5bd838ca83..5e43a5ec3c2 100644 --- a/design-system/website/components/Page.tsx +++ b/design-system/website/components/Page.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import type { HTMLAttributes, ReactNode } from 'react'; import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/design-system/website/components/ReadableColor.tsx b/design-system/website/components/ReadableColor.tsx index b80ec91c592..b6682317433 100644 --- a/design-system/website/components/ReadableColor.tsx +++ b/design-system/website/components/ReadableColor.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import type { ReactNode } from 'react'; import { jsx } from '@keystone-ui/core'; diff --git a/design-system/website/package.json b/design-system/website/package.json index f5816f89485..24fa82c6de3 100644 --- a/design-system/website/package.json +++ b/design-system/website/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-ui/website", - "version": "3.0.1", + "version": "3.0.2", "private": true, "license": "MIT", "scripts": { @@ -8,30 +8,29 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/fields": "^4.1.2", - "@keystone-ui/loading": "^4.0.0", - "@keystone-ui/modals": "^4.0.0", - "@keystone-ui/notice": "^4.0.0", - "@keystone-ui/options": "^4.0.1", - "@keystone-ui/pill": "^5.0.0", - "@keystone-ui/popover": "^4.0.2", - "@keystone-ui/segmented-control": "^4.0.0", - "@keystone-ui/toast": "^4.0.1", - "@keystone-ui/tooltip": "^4.0.0", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/loading": "^4.0.1", + "@keystone-ui/modals": "^4.0.1", + "@keystone-ui/notice": "^4.0.2", + "@keystone-ui/options": "^4.0.2", + "@keystone-ui/pill": "^5.0.1", + "@keystone-ui/popover": "^4.0.3", + "@keystone-ui/segmented-control": "^4.0.3", + "@keystone-ui/toast": "^4.0.3", + "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "@types/react-dom": "^17.0.9", "@types/tinycolor2": "^1.4.3", - "@types/webpack": "^4.41.30", - "next": "^10.2.3", + "next": "^11.1.0", "react": "^17.0.2", "react-dom": "^17.0.2", "tinycolor2": "^1.4.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/design-system/website/pages/components/button.tsx b/design-system/website/pages/components/button.tsx index cf75acdf4d4..6e509f823c4 100644 --- a/design-system/website/pages/components/button.tsx +++ b/design-system/website/pages/components/button.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, Stack } from '@keystone-ui/core'; import { Button, buttonToneValues, ToneKey, buttonWeightValues } from '@keystone-ui/button'; diff --git a/design-system/website/pages/components/fields.tsx b/design-system/website/pages/components/fields.tsx index 06c17d61c8b..eb3674ea35b 100644 --- a/design-system/website/pages/components/fields.tsx +++ b/design-system/website/pages/components/fields.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { ComponentProps, ReactNode, useState } from 'react'; import { jsx, Stack, useTheme } from '@keystone-ui/core'; diff --git a/design-system/website/pages/components/loading.tsx b/design-system/website/pages/components/loading.tsx index 9a7c6de8c22..8a3638f0c47 100644 --- a/design-system/website/pages/components/loading.tsx +++ b/design-system/website/pages/components/loading.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { Fragment } from 'react'; import { jsx, Box, Stack } from '@keystone-ui/core'; diff --git a/design-system/website/pages/components/modals.tsx b/design-system/website/pages/components/modals.tsx index 9b51c043911..da43afd59cb 100644 --- a/design-system/website/pages/components/modals.tsx +++ b/design-system/website/pages/components/modals.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useState } from 'react'; diff --git a/design-system/website/pages/components/notice.tsx b/design-system/website/pages/components/notice.tsx index e073b8c644c..2771491ea4e 100644 --- a/design-system/website/pages/components/notice.tsx +++ b/design-system/website/pages/components/notice.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { Notice, noticeToneValues } from '@keystone-ui/notice'; diff --git a/design-system/website/pages/components/options.tsx b/design-system/website/pages/components/options.tsx index f4ca059b10c..5afe207f008 100644 --- a/design-system/website/pages/components/options.tsx +++ b/design-system/website/pages/components/options.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/design-system/website/pages/components/pill.tsx b/design-system/website/pages/components/pill.tsx index 8188be035e3..189c56cdaf7 100644 --- a/design-system/website/pages/components/pill.tsx +++ b/design-system/website/pages/components/pill.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Stack, jsx } from '@keystone-ui/core'; diff --git a/design-system/website/pages/components/popover.tsx b/design-system/website/pages/components/popover.tsx index 29937eda285..e45e8da6127 100644 --- a/design-system/website/pages/components/popover.tsx +++ b/design-system/website/pages/components/popover.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, Box } from '@keystone-ui/core'; diff --git a/design-system/website/pages/components/toast.tsx b/design-system/website/pages/components/toast.tsx index e0d0f1800ba..ff0bd013d04 100644 --- a/design-system/website/pages/components/toast.tsx +++ b/design-system/website/pages/components/toast.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Button } from '@keystone-ui/button'; diff --git a/design-system/website/pages/components/tooltip.tsx b/design-system/website/pages/components/tooltip.tsx index 9c2400c3043..4bf7d596910 100644 --- a/design-system/website/pages/components/tooltip.tsx +++ b/design-system/website/pages/components/tooltip.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/design-system/website/pages/core/alias-tokens.tsx b/design-system/website/pages/core/alias-tokens.tsx index 9d0776bda4a..84e685bf662 100644 --- a/design-system/website/pages/core/alias-tokens.tsx +++ b/design-system/website/pages/core/alias-tokens.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, useTheme, Inline } from '@keystone-ui/core'; diff --git a/design-system/website/pages/core/global-tokens.tsx b/design-system/website/pages/core/global-tokens.tsx index 7a733cc1998..9bccbb2bd36 100644 --- a/design-system/website/pages/core/global-tokens.tsx +++ b/design-system/website/pages/core/global-tokens.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/design-system/website/pages/core/theme.tsx b/design-system/website/pages/core/theme.tsx index b495bfd3545..4adc94b55da 100644 --- a/design-system/website/pages/core/theme.tsx +++ b/design-system/website/pages/core/theme.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/design-system/website/pages/index.tsx b/design-system/website/pages/index.tsx index 7c8e1efec2a..5d8dcef5687 100644 --- a/design-system/website/pages/index.tsx +++ b/design-system/website/pages/index.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/design-system/website/pages/layout/box.tsx b/design-system/website/pages/layout/box.tsx index 80fffbdeb56..bde7febc397 100644 --- a/design-system/website/pages/layout/box.tsx +++ b/design-system/website/pages/layout/box.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, Box, useTheme } from '@keystone-ui/core'; diff --git a/design-system/website/pages/layout/center.tsx b/design-system/website/pages/layout/center.tsx index f4ec940a3f1..7c3f99c9dd1 100644 --- a/design-system/website/pages/layout/center.tsx +++ b/design-system/website/pages/layout/center.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, Box, useTheme, Center } from '@keystone-ui/core'; diff --git a/design-system/website/pages/layout/stack.tsx b/design-system/website/pages/layout/stack.tsx index 6a8445842bf..29ebc625df6 100644 --- a/design-system/website/pages/layout/stack.tsx +++ b/design-system/website/pages/layout/stack.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, Text, Stack } from '@keystone-ui/core'; diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a1174b7a435..e6a3c1a1b5e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,20 @@ # @keystone-next/website +## 3.1.5 + +### Patch Changes + +- [#6391](https://github.com/keystonejs/keystone/pull/6391) [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41) Thanks [@bladey](https://github.com/bladey)! - Adds support for `introspection` in the Apollo Server config. Introspection enables you to query a GraphQL server for information about the underlying schema. If the playground is enabled then introspection is automatically enabled - unless specifically disabled. + +* [#6443](https://github.com/keystonejs/keystone/pull/6443) [`b45536e22`](https://github.com/keystonejs/keystone/commit/b45536e22f9c3a61c781161602f6f01268b303c7) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused dependency `@types/webpack`. + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +* [#6467](https://github.com/keystonejs/keystone/pull/6467) [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed) Thanks [@JedWatson](https://github.com/JedWatson)! - Add extendExpressApp config option for configuring the express app that Keystone creates + +* Updated dependencies [[`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9)]: + - @keystone-next/fields-document@9.0.0 + ## 3.1.4 ### Patch Changes diff --git a/docs/components/Announce.tsx b/docs/components/Announce.tsx index a42f25ba2bd..a1c01aca983 100644 --- a/docs/components/Announce.tsx +++ b/docs/components/Announce.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes, ReactNode } from 'react'; diff --git a/docs/components/Breadcrumbs.tsx b/docs/components/Breadcrumbs.tsx index b560898d12b..084fb74ffcd 100644 --- a/docs/components/Breadcrumbs.tsx +++ b/docs/components/Breadcrumbs.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; diff --git a/docs/components/DarkModeBtn.tsx b/docs/components/DarkModeBtn.tsx index 2ee0dac49e7..46c509906b1 100644 --- a/docs/components/DarkModeBtn.tsx +++ b/docs/components/DarkModeBtn.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, useState, useEffect, HTMLAttributes } from 'react'; import { jsx, Global } from '@emotion/react'; diff --git a/docs/components/Footer.tsx b/docs/components/Footer.tsx index 11e38538759..c7391fba90a 100644 --- a/docs/components/Footer.tsx +++ b/docs/components/Footer.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import Link from 'next/link'; diff --git a/docs/components/MobileMenu.tsx b/docs/components/MobileMenu.tsx index fb828622cf8..4ffdcda81fb 100644 --- a/docs/components/MobileMenu.tsx +++ b/docs/components/MobileMenu.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import Link from 'next/link'; diff --git a/docs/components/RelatedContent.tsx b/docs/components/RelatedContent.tsx index 425b4cc882b..bc66f26777e 100644 --- a/docs/components/RelatedContent.tsx +++ b/docs/components/RelatedContent.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { ReactNode } from 'react'; diff --git a/docs/components/SkipLinks.tsx b/docs/components/SkipLinks.tsx index 58be593a20e..6a0056727c8 100644 --- a/docs/components/SkipLinks.tsx +++ b/docs/components/SkipLinks.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { AnchorHTMLAttributes, Fragment, useCallback } from 'react'; diff --git a/docs/components/Socials.tsx b/docs/components/Socials.tsx index ef3e7d7c9c8..b2fc296ea22 100644 --- a/docs/components/Socials.tsx +++ b/docs/components/Socials.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/SubscribeForm.tsx b/docs/components/SubscribeForm.tsx index 8d8f9306fe0..d2607f17d42 100644 --- a/docs/components/SubscribeForm.tsx +++ b/docs/components/SubscribeForm.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, useState, ReactNode, SyntheticEvent, HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/Theme.tsx b/docs/components/Theme.tsx index 86c4a8b19ea..201a6ba875e 100644 --- a/docs/components/Theme.tsx +++ b/docs/components/Theme.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, Global } from '@emotion/react'; import { useState, useEffect } from 'react'; diff --git a/docs/components/content/AdvancedReactCta.tsx b/docs/components/content/AdvancedReactCta.tsx index 96071599b91..a5058c4f980 100644 --- a/docs/components/content/AdvancedReactCta.tsx +++ b/docs/components/content/AdvancedReactCta.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/content/CodeBox.tsx b/docs/components/content/CodeBox.tsx index 5d08c0b5336..ee2fe814de9 100644 --- a/docs/components/content/CodeBox.tsx +++ b/docs/components/content/CodeBox.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { HTMLAttributes } from 'react'; import { useToasts } from 'react-toast-notifications'; diff --git a/docs/components/content/CodeWindow.tsx b/docs/components/content/CodeWindow.tsx index 45a296cce75..dbaa5027f55 100644 --- a/docs/components/content/CodeWindow.tsx +++ b/docs/components/content/CodeWindow.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/content/CommunityCta.tsx b/docs/components/content/CommunityCta.tsx index dfb2001721c..e5f17914fdc 100644 --- a/docs/components/content/CommunityCta.tsx +++ b/docs/components/content/CommunityCta.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/content/EndCta.tsx b/docs/components/content/EndCta.tsx index 0ba3a57d846..6f51fc41447 100644 --- a/docs/components/content/EndCta.tsx +++ b/docs/components/content/EndCta.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/content/Intro.tsx b/docs/components/content/Intro.tsx index be083b26e10..4efa0a75260 100644 --- a/docs/components/content/Intro.tsx +++ b/docs/components/content/Intro.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/content/MWrapper.tsx b/docs/components/content/MWrapper.tsx index b620956764b..dfbfae84f78 100644 --- a/docs/components/content/MWrapper.tsx +++ b/docs/components/content/MWrapper.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { ElementType, HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/content/Pill.tsx b/docs/components/content/Pill.tsx index 8042216cf88..8ad9f22da6e 100644 --- a/docs/components/content/Pill.tsx +++ b/docs/components/content/Pill.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/content/Quote.tsx b/docs/components/content/Quote.tsx index 8ba870832a5..7976e0e06cc 100644 --- a/docs/components/content/Quote.tsx +++ b/docs/components/content/Quote.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/content/Section.tsx b/docs/components/content/Section.tsx index 9a91bb81993..104330c1426 100644 --- a/docs/components/content/Section.tsx +++ b/docs/components/content/Section.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/content/TweetBox.tsx b/docs/components/content/TweetBox.tsx index 867c3ddfcb8..bd0ba49a193 100644 --- a/docs/components/content/TweetBox.tsx +++ b/docs/components/content/TweetBox.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import type { HTMLAttributes } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/ComingSoon.tsx b/docs/components/docs/ComingSoon.tsx index a717b2d3bbc..1bac565e554 100644 --- a/docs/components/docs/ComingSoon.tsx +++ b/docs/components/docs/ComingSoon.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/CommunitySlackCTA.tsx b/docs/components/docs/CommunitySlackCTA.tsx index 6e80c6ea914..7139448daab 100644 --- a/docs/components/docs/CommunitySlackCTA.tsx +++ b/docs/components/docs/CommunitySlackCTA.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/CopyToClipboard.tsx b/docs/components/docs/CopyToClipboard.tsx index f1a7902a520..d51ddcac58b 100644 --- a/docs/components/docs/CopyToClipboard.tsx +++ b/docs/components/docs/CopyToClipboard.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useToasts } from 'react-toast-notifications'; import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/DocsFooter.tsx b/docs/components/docs/DocsFooter.tsx index a1dcb788682..a4cf69e8bb7 100644 --- a/docs/components/docs/DocsFooter.tsx +++ b/docs/components/docs/DocsFooter.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/DocumentEditorDemo.tsx b/docs/components/docs/DocumentEditorDemo.tsx index 31f49faf7ae..e35fe09879f 100644 --- a/docs/components/docs/DocumentEditorDemo.tsx +++ b/docs/components/docs/DocumentEditorDemo.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { getInitialPropsValue } from '@keystone-next/fields-document/src/DocumentEditor/component-blocks/initial-values'; import { FormValueContent } from '@keystone-next/fields-document/src/DocumentEditor/component-blocks/form'; @@ -90,7 +91,7 @@ const componentBlocks = { type DocumentFieldConfig = Parameters[0]; function documentFeaturesCodeExample(config: DocumentFieldConfig | DocumentFeatures) { - return `import { config, createSchema, list } from '@keystone-next/keystone/schema'; + return `import { config, createSchema, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export default config({ diff --git a/docs/components/docs/ExamplesList.tsx b/docs/components/docs/ExamplesList.tsx index ec56892d60e..a91c22f47de 100644 --- a/docs/components/docs/ExamplesList.tsx +++ b/docs/components/docs/ExamplesList.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/GitHubExamplesCTA.tsx b/docs/components/docs/GitHubExamplesCTA.tsx index 9f1d6c700ad..8ec3b47aac7 100644 --- a/docs/components/docs/GitHubExamplesCTA.tsx +++ b/docs/components/docs/GitHubExamplesCTA.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/Heading.tsx b/docs/components/docs/Heading.tsx index 80e90458766..677ad9cf44f 100644 --- a/docs/components/docs/Heading.tsx +++ b/docs/components/docs/Heading.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import slugify from '@sindresorhus/slugify'; import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/Navigation.tsx b/docs/components/docs/Navigation.tsx index 4540d6ded9b..c9bb7ef664f 100644 --- a/docs/components/docs/Navigation.tsx +++ b/docs/components/docs/Navigation.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { AnchorHTMLAttributes, HTMLAttributes, ReactNode } from 'react'; import parseISO from 'date-fns/parseISO'; @@ -182,7 +183,9 @@ export function DocsNavigation() { Config API Schema API Fields API - Access Control API + + Access Control API Updated + Hooks API Session API Authentication API @@ -224,6 +227,10 @@ export function UpdatesNavigation({ releases = [] }: { releases: string[] }) { ) : null}
    + + +   New Access Control API +   New GraphQL API diff --git a/docs/components/docs/TableOfContents.tsx b/docs/components/docs/TableOfContents.tsx index 4fc1f5164d6..3dabb8da5e0 100644 --- a/docs/components/docs/TableOfContents.tsx +++ b/docs/components/docs/TableOfContents.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useState, useEffect } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/docs/WalkthroughsList.tsx b/docs/components/docs/WalkthroughsList.tsx index 5c8718649df..33c4fd8fea5 100644 --- a/docs/components/docs/WalkthroughsList.tsx +++ b/docs/components/docs/WalkthroughsList.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/ArrowR.tsx b/docs/components/icons/ArrowR.tsx index da731c12520..6de9e75a170 100644 --- a/docs/components/icons/ArrowR.tsx +++ b/docs/components/icons/ArrowR.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Automated.tsx b/docs/components/icons/Automated.tsx index 65cb0e19b66..9dcb6ebdf8a 100644 --- a/docs/components/icons/Automated.tsx +++ b/docs/components/icons/Automated.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Cli.tsx b/docs/components/icons/Cli.tsx index 08745eb6c1f..7f537654c2f 100644 --- a/docs/components/icons/Cli.tsx +++ b/docs/components/icons/Cli.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/ClientLogos.tsx b/docs/components/icons/ClientLogos.tsx index 7a838b18573..7507ca9f37e 100644 --- a/docs/components/icons/ClientLogos.tsx +++ b/docs/components/icons/ClientLogos.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Close.tsx b/docs/components/icons/Close.tsx index 987a5166252..e530eb84720 100644 --- a/docs/components/icons/Close.tsx +++ b/docs/components/icons/Close.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Code.tsx b/docs/components/icons/Code.tsx index 67bbaf7a7f2..f7affa9764f 100644 --- a/docs/components/icons/Code.tsx +++ b/docs/components/icons/Code.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Content.tsx b/docs/components/icons/Content.tsx index 34178f1117d..e093b9faeb1 100644 --- a/docs/components/icons/Content.tsx +++ b/docs/components/icons/Content.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Copy.tsx b/docs/components/icons/Copy.tsx index 720eac68d66..4949ad2c36f 100644 --- a/docs/components/icons/Copy.tsx +++ b/docs/components/icons/Copy.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Custom.tsx b/docs/components/icons/Custom.tsx index 416c95f3070..407b0104615 100644 --- a/docs/components/icons/Custom.tsx +++ b/docs/components/icons/Custom.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/DarkMode.tsx b/docs/components/icons/DarkMode.tsx index c37a92d3bb7..fbf0cd0606e 100644 --- a/docs/components/icons/DarkMode.tsx +++ b/docs/components/icons/DarkMode.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Docs.tsx b/docs/components/icons/Docs.tsx index 6c62fc47bba..4ff60b1fc3a 100644 --- a/docs/components/icons/Docs.tsx +++ b/docs/components/icons/Docs.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Edit.tsx b/docs/components/icons/Edit.tsx index b700a60003d..6eeac8cdbdb 100644 --- a/docs/components/icons/Edit.tsx +++ b/docs/components/icons/Edit.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Editor.tsx b/docs/components/icons/Editor.tsx index 3708af75f21..7e5c8e8c40c 100644 --- a/docs/components/icons/Editor.tsx +++ b/docs/components/icons/Editor.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Filter.tsx b/docs/components/icons/Filter.tsx index 90ed77a83a6..dd87f7d4bdf 100644 --- a/docs/components/icons/Filter.tsx +++ b/docs/components/icons/Filter.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/FrontEndLogos.tsx b/docs/components/icons/FrontEndLogos.tsx index 1ae7b07710d..241b0813961 100644 --- a/docs/components/icons/FrontEndLogos.tsx +++ b/docs/components/icons/FrontEndLogos.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { SVGAttributes } from 'react'; diff --git a/docs/components/icons/GitHub.tsx b/docs/components/icons/GitHub.tsx index 1d5deb6142b..338c2b39942 100644 --- a/docs/components/icons/GitHub.tsx +++ b/docs/components/icons/GitHub.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/GraphQl.tsx b/docs/components/icons/GraphQl.tsx index 3f080622c4d..198ade91006 100644 --- a/docs/components/icons/GraphQl.tsx +++ b/docs/components/icons/GraphQl.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Hamburger.tsx b/docs/components/icons/Hamburger.tsx index 691c9393596..110d9103b41 100644 --- a/docs/components/icons/Hamburger.tsx +++ b/docs/components/icons/Hamburger.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Keystone.tsx b/docs/components/icons/Keystone.tsx index 81287bba8d0..b63532b661e 100644 --- a/docs/components/icons/Keystone.tsx +++ b/docs/components/icons/Keystone.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Lab.tsx b/docs/components/icons/Lab.tsx index 79f7f5e4689..d4f34bdaa88 100644 --- a/docs/components/icons/Lab.tsx +++ b/docs/components/icons/Lab.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/LightMode.tsx b/docs/components/icons/LightMode.tsx index 7ecf2e03571..b9947154db8 100644 --- a/docs/components/icons/LightMode.tsx +++ b/docs/components/icons/LightMode.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Link.tsx b/docs/components/icons/Link.tsx index b6cd16565df..9635812f45c 100644 --- a/docs/components/icons/Link.tsx +++ b/docs/components/icons/Link.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Migration.tsx b/docs/components/icons/Migration.tsx index 03c8ea1e528..81dc8431404 100644 --- a/docs/components/icons/Migration.tsx +++ b/docs/components/icons/Migration.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Nextjs.tsx b/docs/components/icons/Nextjs.tsx index bcb75fac372..70ebb7b9688 100644 --- a/docs/components/icons/Nextjs.tsx +++ b/docs/components/icons/Nextjs.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Organization.tsx b/docs/components/icons/Organization.tsx index e0b4392bf27..7ca4dac5897 100644 --- a/docs/components/icons/Organization.tsx +++ b/docs/components/icons/Organization.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Postgres.tsx b/docs/components/icons/Postgres.tsx index 7a28a7480df..980efd15af7 100644 --- a/docs/components/icons/Postgres.tsx +++ b/docs/components/icons/Postgres.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Prisma.tsx b/docs/components/icons/Prisma.tsx index 618b943910a..2c5be6e3608 100644 --- a/docs/components/icons/Prisma.tsx +++ b/docs/components/icons/Prisma.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Profile.tsx b/docs/components/icons/Profile.tsx index 1bb976b0db0..c2565cf2303 100644 --- a/docs/components/icons/Profile.tsx +++ b/docs/components/icons/Profile.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Quote.tsx b/docs/components/icons/Quote.tsx index 27edfadfa34..ade4ad5a09f 100644 --- a/docs/components/icons/Quote.tsx +++ b/docs/components/icons/Quote.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Relational.tsx b/docs/components/icons/Relational.tsx index c81952270a0..599608d3e10 100644 --- a/docs/components/icons/Relational.tsx +++ b/docs/components/icons/Relational.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Relationship.tsx b/docs/components/icons/Relationship.tsx index 72759b38dce..a06fd9a8c3d 100644 --- a/docs/components/icons/Relationship.tsx +++ b/docs/components/icons/Relationship.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Roadmap.tsx b/docs/components/icons/Roadmap.tsx index 5b6514d3a03..cbbf4d90380 100644 --- a/docs/components/icons/Roadmap.tsx +++ b/docs/components/icons/Roadmap.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Search.tsx b/docs/components/icons/Search.tsx index 460fd2e993d..ca542027c06 100644 --- a/docs/components/icons/Search.tsx +++ b/docs/components/icons/Search.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/SearchKeys.tsx b/docs/components/icons/SearchKeys.tsx index 86375ebb16f..6a8494d3dee 100644 --- a/docs/components/icons/SearchKeys.tsx +++ b/docs/components/icons/SearchKeys.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Shield.tsx b/docs/components/icons/Shield.tsx index a46f5cd00cb..478a60c6585 100644 --- a/docs/components/icons/Shield.tsx +++ b/docs/components/icons/Shield.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Slack.tsx b/docs/components/icons/Slack.tsx index 4f26dc144ac..167b904f244 100644 --- a/docs/components/icons/Slack.tsx +++ b/docs/components/icons/Slack.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Thinkmill.tsx b/docs/components/icons/Thinkmill.tsx index 022b408399f..b9ec06a82f2 100644 --- a/docs/components/icons/Thinkmill.tsx +++ b/docs/components/icons/Thinkmill.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Tick.tsx b/docs/components/icons/Tick.tsx index 95653bc2c96..dd0ff74cadf 100644 --- a/docs/components/icons/Tick.tsx +++ b/docs/components/icons/Tick.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Twitter.tsx b/docs/components/icons/Twitter.tsx index fd0a2b34831..50f8d55f43a 100644 --- a/docs/components/icons/Twitter.tsx +++ b/docs/components/icons/Twitter.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Typescript.tsx b/docs/components/icons/Typescript.tsx index c2b28f4f184..a4fc5f6083e 100644 --- a/docs/components/icons/Typescript.tsx +++ b/docs/components/icons/Typescript.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Updates.tsx b/docs/components/icons/Updates.tsx index c022d7b82f5..b7a9c4f0397 100644 --- a/docs/components/icons/Updates.tsx +++ b/docs/components/icons/Updates.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Watch.tsx b/docs/components/icons/Watch.tsx index 5ad6a8249b0..0f97af14f3f 100644 --- a/docs/components/icons/Watch.tsx +++ b/docs/components/icons/Watch.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/Welcome.tsx b/docs/components/icons/Welcome.tsx index 8c641905be0..36c8ffcb289 100644 --- a/docs/components/icons/Welcome.tsx +++ b/docs/components/icons/Welcome.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/WhyKeystone.tsx b/docs/components/icons/WhyKeystone.tsx index e8f2c5509ef..7d2a59ca37b 100644 --- a/docs/components/icons/WhyKeystone.tsx +++ b/docs/components/icons/WhyKeystone.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/icons/util.tsx b/docs/components/icons/util.tsx index 1e91c02b04b..e94238486e1 100644 --- a/docs/components/icons/util.tsx +++ b/docs/components/icons/util.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { SVGAttributes } from 'react'; diff --git a/docs/components/primitives/Alert.tsx b/docs/components/primitives/Alert.tsx index 8bba89afeda..717bc221229 100644 --- a/docs/components/primitives/Alert.tsx +++ b/docs/components/primitives/Alert.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import classnames from 'classnames'; diff --git a/docs/components/primitives/Badge.tsx b/docs/components/primitives/Badge.tsx index e0c852cd084..5a01d909153 100644 --- a/docs/components/primitives/Badge.tsx +++ b/docs/components/primitives/Badge.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/primitives/Button.tsx b/docs/components/primitives/Button.tsx index 39f224c6caf..082feb0bcb1 100644 --- a/docs/components/primitives/Button.tsx +++ b/docs/components/primitives/Button.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, FunctionComponent, ReactNode } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/components/primitives/Code.tsx b/docs/components/primitives/Code.tsx index abd3c89fccb..d9e7857b017 100644 --- a/docs/components/primitives/Code.tsx +++ b/docs/components/primitives/Code.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import Highlight, { Language, Prism } from 'prism-react-renderer'; import { jsx } from '@emotion/react'; diff --git a/docs/components/primitives/Emoji.tsx b/docs/components/primitives/Emoji.tsx index 4e4db0ba548..4e213356e01 100644 --- a/docs/components/primitives/Emoji.tsx +++ b/docs/components/primitives/Emoji.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, keyframes } from '@emotion/react'; import { useRef, useState, useEffect, HTMLAttributes, ReactNode } from 'react'; diff --git a/docs/components/primitives/Field.tsx b/docs/components/primitives/Field.tsx index 88f7bf0658d..3cd6d911050 100644 --- a/docs/components/primitives/Field.tsx +++ b/docs/components/primitives/Field.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { forwardRef, InputHTMLAttributes } from 'react'; diff --git a/docs/components/primitives/GitHubButton.tsx b/docs/components/primitives/GitHubButton.tsx index 018433d8081..1ecb3cce7fb 100644 --- a/docs/components/primitives/GitHubButton.tsx +++ b/docs/components/primitives/GitHubButton.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { useState, useEffect, HTMLAttributes } from 'react'; diff --git a/docs/components/primitives/Gradient.tsx b/docs/components/primitives/Gradient.tsx index 43a07f05a7d..18e3e31cd02 100644 --- a/docs/components/primitives/Gradient.tsx +++ b/docs/components/primitives/Gradient.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes, ElementType } from 'react'; diff --git a/docs/components/primitives/Highlight.tsx b/docs/components/primitives/Highlight.tsx index 664da7b566a..2d61a569488 100644 --- a/docs/components/primitives/Highlight.tsx +++ b/docs/components/primitives/Highlight.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes, ElementType } from 'react'; diff --git a/docs/components/primitives/Loading.tsx b/docs/components/primitives/Loading.tsx index f9a0d9adb61..bf4179894d7 100644 --- a/docs/components/primitives/Loading.tsx +++ b/docs/components/primitives/Loading.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, keyframes } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/primitives/SearchField.tsx b/docs/components/primitives/SearchField.tsx index e3d9a3427c4..d9ae4238314 100644 --- a/docs/components/primitives/SearchField.tsx +++ b/docs/components/primitives/SearchField.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, Global, css } from '@emotion/react'; import { Fragment, HTMLAttributes } from 'react'; diff --git a/docs/components/primitives/Stack.tsx b/docs/components/primitives/Stack.tsx index 7d6c377a20a..da56527cfee 100644 --- a/docs/components/primitives/Stack.tsx +++ b/docs/components/primitives/Stack.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import { HTMLAttributes } from 'react'; diff --git a/docs/components/primitives/Status.tsx b/docs/components/primitives/Status.tsx index c76bde85806..ef4ea027fe8 100644 --- a/docs/components/primitives/Status.tsx +++ b/docs/components/primitives/Status.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/primitives/Type.tsx b/docs/components/primitives/Type.tsx index 32c66f41bb7..9eb505b7820 100644 --- a/docs/components/primitives/Type.tsx +++ b/docs/components/primitives/Type.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/components/primitives/Well.tsx b/docs/components/primitives/Well.tsx index c087f5b7213..0bb149d20c1 100644 --- a/docs/components/primitives/Well.tsx +++ b/docs/components/primitives/Well.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import Link from 'next/link'; diff --git a/docs/components/primitives/Wrapper.tsx b/docs/components/primitives/Wrapper.tsx index f3d72fde64d..15dd4ad82e9 100644 --- a/docs/components/primitives/Wrapper.tsx +++ b/docs/components/primitives/Wrapper.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import type { ElementType, HTMLAttributes } from 'react'; diff --git a/docs/next-env.d.ts b/docs/next-env.d.ts index 6ab0ecc22f4..9bc3dd46b9d 100644 --- a/docs/next-env.d.ts +++ b/docs/next-env.d.ts @@ -1,4 +1,3 @@ -// @ts-ignore /// /// /// diff --git a/docs/package.json b/docs/package.json index 3cbf96ebd5f..77ee923757a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/website", - "version": "3.1.4", + "version": "3.1.5", "private": true, "license": "MIT", "scripts": { @@ -18,7 +18,7 @@ "@emotion/react": "^11.4.1", "@emotion/server": "11.4.0", "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/fields-document": "^8.0.0", + "@keystone-next/fields-document": "^9.0.0", "@mdx-js/loader": "next", "@mdx-js/react": "^1.6.22", "@next/mdx": "^11.1.0", @@ -26,16 +26,15 @@ "@sindresorhus/slugify": "^1.1.2", "@types/gtag.js": "^0.0.7", "@types/mdx-js__react": "^1.5.4", - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "@types/react-dom": "^17.0.9", - "@types/webpack": "^4.41.30", "classnames": "^2.3.1", "copy-to-clipboard": "^3.3.1", "cypress": "^5.6.0", "date-fns": "^2.23.0", "facepaint": "^1.2.1", "lodash.debounce": "^4.0.8", - "next": "npm:next@^11.1.0", + "next": "^11.1.0", "next-compose-plugins": "^2.2.1", "prism-react-renderer": "^1.2.1", "react": "^17.0.2", @@ -47,9 +46,9 @@ }, "devDependencies": { "@types/lodash.debounce": "^4.0.6", - "next-sitemap": "^1.6.157", + "next-sitemap": "^1.6.164", "start-server-and-test": "^1.13.1", - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/docs/pages/404.tsx b/docs/pages/404.tsx index 0478f55a62a..e9984dacc1b 100644 --- a/docs/pages/404.tsx +++ b/docs/pages/404.tsx @@ -29,11 +29,13 @@ function ConstructionIllustration() { ); } +// Modifying this code may have security implications +// See.. https://github.com/keystonejs/keystone/pull/6411#issuecomment-906085389 const v5PathList = ['/tutorials', '/guides', '/keystonejs', '/api', '/discussions']; export default function NotFoundPage() { const { asPath } = useRouter(); - const tryV5Link = v5PathList.some(i => asPath.startsWith(i)); + const tryV5Link = asPath.startsWith('/') && v5PathList.some(i => asPath.startsWith(i)); return (
    If you were looking for a page in the Keystone 5 docs, try{' '} - v5.keystonejs.com{asPath}. + https://v5.keystonejs.com{asPath}. ) : null} diff --git a/docs/pages/_app.tsx b/docs/pages/_app.tsx index 3a28c3c6506..e30d62f53e5 100644 --- a/docs/pages/_app.tsx +++ b/docs/pages/_app.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ToastProvider } from 'react-toast-notifications'; import { jsx, Global, css } from '@emotion/react'; diff --git a/docs/pages/_document.tsx b/docs/pages/_document.tsx index 74898316d13..e9192e8dc81 100644 --- a/docs/pages/_document.tsx +++ b/docs/pages/_document.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'; import React from 'react'; diff --git a/docs/pages/docs/apis/access-control.mdx b/docs/pages/docs/apis/access-control.mdx index d408568a48d..a1d4a6659b0 100644 --- a/docs/pages/docs/apis/access-control.mdx +++ b/docs/pages/docs/apis/access-control.mdx @@ -2,11 +2,12 @@ import { Markdown } from '../../../components/Markdown'; # Access Control API -The `access` property of the [list configuration](./schema) and [field configuration](./fields) objects configures who can read, create, update, and delete items in your Keystone system. +The `access` property of the [list configuration](./schema) object configures who can query, create, update, and delete items in your Keystone system. +The `access` property of the [field configuration](./fields) object configures who can read, create, and update specific field values of an item. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -20,256 +21,190 @@ export default config({ }); ``` -This document covers the complete access control API. -For a guide on how to use this API to apply common patterns please see the [access control guide](../guides/access-control). +!> This document covers the complete access control API. +Our [access control guide](../guides/access-control) shows you how to apply this API to common patterns. ## List Access Control -Keystone allows you to set up access control on a per-list basis. -The default access control is to allow all operations for all users. -Access control is applied to the generated CRUD (**c**reate, **r**ead, **u**pdate, **d**elete) queries and mutations in the [GraphQL API](./graphql). -Access control is applied before any [hooks](./hooks) are executed. +Keystone lets you apply access control on a per-list basis. +By default it allows all operations for all users. +Access control is applied to the generated CRUD operations and mutations in the [GraphQL API](./graphql), and is applied before any [hooks](./hooks) are executed. -You can specify access control using either **concise** or **verbose** syntax. -Verbose syntax provides a separate access control rule for each operation type; `create`, `read`, `update`, and `delete`. -Concise syntax provides a single access control rule which is used for all operation types. +List-level access control can be specified in three ways. -```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; - -export default config({ - lists: createSchema({ - ListKey: list({ - // Concise access control definition - access: true, - // Verbose access control definition - access: { - create: true, - read: true, - update: true, - delete: true, - }, - }), - }), -}); -``` +- [`operation`](#operation) access control lets you check the information in the `context` and `session` objects to decide if the + user is allowed to access the list. +- [`filter`](#filter) access control lets you provide a GraphQL filter to restrict the items the user is allowed to access. +- [`item`](#item) access control lets you write a function which inspects the provided input data and the existing object (if it exists) + and make a decision based on this extra data. -When using verbose syntax, any operation which is not specified will default to `true`. +!> **Access denied:** **Mutations** return `null` data with an access denied error. **Queries** never return access denied errors, and instead treat items as if they didn't exist. -The examples below will all use the concise syntax, however the various access control rules can all be applied using verbose syntax. +If access is **denied** due to any of the access control methods, the following responses will be returned from the GraphQL API: -There are three different ways you can specify access-control rules: **static**, **declarative**, and **imperative**. +- **Mutations** + - **Single** operations return `null` and an access denied error. + - **Multi** operations return a data array with `null` values for the items which have access denied. + Error responses are returned for each `null` item. +- **Queries** + - **Single** item queries return `null` with no errors. + - **Many** item queries filter out items which have access denied. No error responses are returned. + - **Count** queries will only count those items for which access is **not** denied. No error responses are returned. -### Static (list) +### Operation -Static access control rules are simple boolean values. -A value of `true` indicates that all users can perform the operation. -A value of `false` indicates that no users can perform the operation. +Operation-level access control lets you control which operations can be accessed by a user based on the `session` and `context`. +Individual functions can be provided for each of the operations. -A static value of `false` implies that the operation can never be executed. -As such, Keystone will exclude the related operations and types from the GraphQL API. -For example, if you set `{ create: false }` then the mutations `createItem` and `createItems` will be removed from the GraphQL API. -If you want to keep the operations in the GraphQL API while preventing all access, you can use the [imperative](#imperative-list) access control rule `() => false`. -The excluded operations can still be access by using [`context.sudo()`](./context#new-context-creators). +!> These functions must return `true` if the operation is allowed, or `false` if it is not allowed. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; export default config({ lists: createSchema({ ListKey: list({ - // Static access control definition - access: true, + access: { + operation: { + query: ({ session, context, listKey, operation }) => true, + create: ({ session, context, listKey, operation }) => true, + update: ({ session, context, listKey, operation }) => true, + delete: ({ session, context, listKey, operation }) => true, + } + }, }), }), }); ``` -### Declarative (list) +?> The `query` access control rule is applied when running GraphQL query operations. +It does not prevent a user **reading** the data returned by the mutation operations. +You should ensure that your `create`, `update`, and `delete` are also configured to prevent access to protected data. + +### Filter -Declarative access control rules are GraphQL `where` statements which are used as additional filters when looking up items as part of read, update, or delete operations. -The access control rule can be any valid clause which could be applied as a `where` filter to the list in the [GraphQL API](./graphql). +Filter-level access control lets you restrict which items can be operated on by providing a function which returns a GraphQL filter. -For read operations, the access control rule is merged with any other filters in the query, and only those items which match the merged filter are returned. +- For **mutations**, the access control filter will be combined with the unique identifier provided to the operation, and access will be denied if no item is found with this combined filter. +- For **queries**, the access control filter will be combined with the query filter and only items which match both filters will be returned. -For update and delete operations, the access control rule is merged with the `id` value to form a filter. -For singular operations, e.g. `updateItem` or `deleteItem`, if the merged filter does not return an item then the mutation will return an `Access Denied` error. -For multi-item operations, e.g. `updateItems` or `deleteItems`, if the merged filter excludes items then these will simply be ignored by the operation, giving the same behaviour as if the ID was missing. +In general, the filter access control functions will return GraphQL filters. +They can also return boolean values `true` or `false` to match or exclude all items. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { checkbox } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ ListKey: list({ - fields: { isLocked: checkbox() }, - // Declarative access control definition - access: { isLocked: { equals: false } }, + fields: { + isReadable: checkbox(), + isUpdatable: checkbox(), + isDeletable: checkbox(), + } + access: { + filter: { + query: ({ session, context, listKey, operation }) => { + return { isReadable: { equals: true } }; + }, + update: ({ session, context, listKey, operation }) => { + return { isUpdatable: { equals: true } }; + }, + delete: ({ session, context, listKey, operation }) => { + return { isDeletable: { equals: true } }; + }, + } + }, }), }), }); ``` -Declarative access control cannot be used for the `create` operation, as there is no filter being applied when creating an item. -If you use declarative access control with the `create` operation, or with concise syntax, it is equivalent to the static access control definition `true` for create operations. - -Declarative access control rules are rarely used directly. -A more common pattern is to return a declarative access control rule from an [imperative](#imperative-list) rule. +!> Filter access control cannot be used on `create` operations, as there is no pre-existing item to filter against. +To restrict `create` operations configure either `access.operation.create` or `access.item.create`. -### Imperative (list) +### Item (mutations only) -Imperative access control rules are functions which return either a boolean value or a [declarative](#declarative-list) value (i.e. a GraphQL `where` clause). -Imperative access control functions can be either synchronous or async. -The function is passed a set of arguments which depends on the operation being performed. -For multi-valued operations the function is only called once, and must evaluate the entire operation as a whole. +`item` is the final and most powerful level of access control. +It’s available to `create`, `update`, and `delete` mutations, and lets you write functions which have access to: -If the function returns: +- the **input data** of the mutation (for `create` and `update` operations), and +- the **existing item** in the database (for `update` and `delete` operations). -- `false` then an `Access Denied` error will be returned. -- `true` then the operation will be allowed. -- **a declarative value** then this will be applied to the operation as described [above](#declarative-list). +!> These functions must return `true` if the operation is allowed, or `false` if it is not allowed. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { checkbox } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ ListKey: list({ - // Imperative access control definition - access: args => true, + access: { + item: { + create: ({ session, context, listKey, operation, originalInput }) => true, + update: ({ session, context, listKey, operation, originalInput, item }) => true, + delete: ({ session, context, listKey, operation, item }) => true, + } + }, }), }), }); ``` -#### Imperative Function Arguments +?> Item-level access control is not available for `query` operations. +Applying access control after fetching items would lead to inconsistent pagination behaviour and incorrect `count` results. -Imperative access control functions are passed a collection of arguments which can be used to determine whether the operation is allowed. +### Function Arguments -| Argument | Description | -| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `listKey` | The key of the list being operated on. | -| `operation` | The CRUD operation being performed (`'create'`, `'read'`, `'update'`, `'delete'`). | -| `session` | The current session object. See the [Sessions API](./session) for details. | -| `originalInput` | For `create` and `update` operations, this is the value of `data` passed into the mutation. For `read` and `delete` operations this value is `undefined`. | -| `itemId` | The `id` of the item being updated/deleted in `update` and `delete` operations. `undefined` for other operations. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +List-level access control functions are passed a collection of arguments which can be used to determine whether the operation is allowed. -```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; - -export default config({ - lists: createSchema({ - ListKey: list({ - // Imperative access control definition - access: ({ - listKey, - operation, - session, - originalInput, - itemId, - context, - }) => { - return true; - }, - }), - }), -}); -``` +| Argument | Description | +| --------------- | ------------------------------------------------------------------------------------------------------------- | +| `session` | The current session object. See the [Sessions API](./session) for details. | +| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| `listKey` | The key of the list being operated on. | +| `operation` | The operation being performed (`'query'`, `'create'`, `'update'`, `'delete'`). | +| `originalInput` | For `create` and `update` operations, this is the value of `data` passed into the mutation. (Item level only) | +| `item` | The existing item being updated/deleted in `update` and `delete` operations. (Item level only) | ## Field Access Control Keystone also allows you to set up access control on a per-field basis. -The default access control is to follow the access control rules for the parent list. -Access control is applied to the generated CRU (**c**reate, **r**ead, **u**pdate, but not delete) queries and mutations in the [GraphQL API](./graphql). -Field access control is applied after list access control has been applied. +Rules can be set for `read`, `update` and `delete` operations. -You can specify access control using either **concise** or **verbose** syntax. -Verbose syntax provides a separate access control rule for each operation type; `create`, `read`, and `update`. -Concise syntax provides a single access control rule which is used for all operation types. +!> Each operation is defined by a function which returns `true` if access is allowed and `false` if access is not allowed. -```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +### Mutations -export default config({ - lists: createSchema({ - ListKey: list({ - fields: { - fieldName: text({ - // Concise access control definition - access: true, - // Verbose access control definition - access: { - create: true, - read: true, - update: true, - }, - }), - }, - }), - }), -}); -``` - -When using verbose syntax, any operation which is not specified will default to `true`. +Field-level access control rules are applied **after** the list level access rules have been applied. +Access control rules are only applied to the fields that have an input value provided to the mutation. +If any of the provided fields fail their access control check, the whole operation is aborted. +The GraphQL API then returns `null` along with an access denied error. -The examples below will all use the concise syntax, however the various access control rules can all be applied using verbose syntax. +### Read -There are two different ways you can specify field access-control rules: **static** and **imperative**. +Field-level access control rules are applied when trying to resolve a field on the output type. +If access is denied then the query will still return an item object, but the specific field will return `null`. +No errors will be returned for `read` access denied. -### Static (field) - -Static access control rules are simple boolean values. -A value of `true` indicates that all users can perform the operation. -A value of `false` indicates that no users can perform the operation. - -A static value of `false` implies that the operation can never be executed. -As such, Keystone will exclude the field from the related operations and types in the GraphQL API. -For example, if you set `{ update: false }` then the field would not appear in the `ItemUpdateInput` and `ItemsUpdateInputs` types of the GraphQL API. -If you want to keep the fields in the GraphQL API while preventing all access, you can use the [imperative](#imperative-list) access control rule `() => false`. -The excluded operations can still be access by using [`context.sudo()`](./context#new-context-creators). +!> The `read` access control is applied to fields returned from both **queries** and **mutations**. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ ListKey: list({ fields: { fieldName: text({ - // Static access control definition - access: true, - }), - }, - }), - }), -}); -``` - -### Imperative (field) - -Imperative access control rules are functions which return a boolean value. -Imperative access control functions can be either synchronous or async. -The function is passed a set of arguments which depends on the operation being performed. -For multi-valued operations the function is called once per item, and must evaluate each item being operated on individually. - -If the function returns `false` then an `Access Denied` error will be returned. -If the function returns `true` then the operation will be allowed. - -```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; - -export default config({ - lists: createSchema({ - ListKey: list({ - fields: { - fieldName: text({ - // Imperative access control definition - access: args => true, + access: { + read: ({ session, context, listKey, fieldKey, operation, item }) => true, + create: ({ session, context, listKey, fieldKey, operation, originalInput }) => true, + update: ({ session, context, listKey, fieldKey, operation, originalInput, item }) => true, + }, }), }, }), @@ -277,46 +212,20 @@ export default config({ }); ``` -#### Imperative Function Arguments - -Imperative access control functions are passed a collection of arguments which can be used to determine whether the operation is allowed. +!> Field-level access control is not available for `delete` operations. To restrict `create` operations configure either `access.operation.delete`, `access.filter.delete` or `access.item.delete` at the list level. -| Argument | Description | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `listKey` | The key of the list being operated on. | -| `fieldKey` | The key of the field being operated on. | -| `operation` | The CRU operation being performed (`'create'`, `'read'`, `'update'`). | -| `session` | The current session object. See the [Sessions API](./session) for details. | -| `originalInput` | For `create` and `update` operations, this is the value of `data` passed into the mutation. For `read` operations this value is `undefined`. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | -| `item` | The item being updated, deleted, or read. This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | +### Function Arguments -```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +Field-level access control functions are passed a collection of arguments which can be used to determine whether the operation is allowed. -export default config({ - lists: createSchema({ - ListKey: list({ - fields: { - fieldName: text({ - // Imperative access control definition - access: ({ - listKey, - fieldKey, - operation, - session, - originalInput, - context, - item, - }) => { - return true; - }, - }), - }, - }), - }), -}); -``` +| Argument | Description | +| --------------- | ------------------------------------------------------------------------------------------- | +| `session` | The current session object. See the [Sessions API](./session) for details. | +| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| `listKey` | The key of the list being operated on. | +| `fieldKey` | The key of the field being operated on. | +| `operation` | The operation being performed (`'read'`, `'create'`, `'update'`). | +| `originalInput` | For `create` and `update` operations, this is the value of `data` passed into the mutation. | +| `item` | The existing item being read/updated in `read` and `update` operations. | export default ({ children }) => {children}; diff --git a/docs/pages/docs/apis/auth.mdx b/docs/pages/docs/apis/auth.mdx index 3c12f781d46..6b63dd5b3ad 100644 --- a/docs/pages/docs/apis/auth.mdx +++ b/docs/pages/docs/apis/auth.mdx @@ -10,8 +10,8 @@ Additional options to this function provide support for creating an initial item For examples of how to use authentication in your system please see the [authentication guide](../guides/auth). ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text, password, checkbox } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text, password, checkbox } from '@keystone-next/keystone/fields'; import { createAuth } from '@keystone-next/auth'; const { withAuth } = createAuth({ @@ -42,7 +42,7 @@ export default withAuth( lists: createSchema({ User: list({ fields: { - email: text({ isUnique: true }), + email: text({ isIndexed: 'unique', isFilterable: true }), password: password(), isAdmin: checkbox(), }, @@ -62,7 +62,7 @@ The `createAuth` function must be used in conjunction with a [session](./session The core functionality of the authentication system provides a GraphQL mutation to authenticate a user and then start a session, and a sign in page in the Admin UI. - `listKey`: The name of the list to authenticate against. -- `identityField`: The name of the field to use as an identity field. This field must have `{ isUnique: true }` set. +- `identityField`: The name of the field to use as an identity field. This field must have `{ isIndexed: 'unique', isFilterable: true }` set. - `secretField`: The name of the field to use as a secret. This field must be a `password()` field type. ```typescript diff --git a/docs/pages/docs/apis/config.mdx b/docs/pages/docs/apis/config.mdx index 249781d2507..1a80e925d41 100644 --- a/docs/pages/docs/apis/config.mdx +++ b/docs/pages/docs/apis/config.mdx @@ -8,7 +8,7 @@ import { InlineCode } from '../../../components/primitives/Code'; The `keystone-next` [CLI](../guides/cli) expects to find a module named `keystone.ts` with a default export of a Keystone system configuration returned from the function `config()`. ```typescript filename=keystone.ts -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; export default config({ /* ... */ }); ``` @@ -31,7 +31,7 @@ export default config({ We will cover each of these options below. -The configuration object has a TypeScript type of `KeystoneConfig`, which can be imported from `@keystone-next/types`. +The configuration object has a TypeScript type of `KeystoneConfig`, which can be imported from `@keystone-next/keystone/types`. This type definition should be considered the source of truth for the available configuration options. ## lists @@ -43,8 +43,8 @@ In general you will use the `createSchema()` function to create this configurati See the [Schema API](./schema) docs for details on how to use this function. ```typescript -import type { ListSchemaConfig } from '@keystone-next/types'; -import { config, createSchema } from '@keystone-next/keystone/schema'; +import type { ListSchemaConfig } from '@keystone-next/keystone/types'; +import { config, createSchema } from '@keystone-next/keystone'; export default config({ lists: createSchema({ /* ... */ }), @@ -55,7 +55,7 @@ export default config({ ## db ``` -import type { DatabaseConfig } from '@keystone-next/types'; +import type { DatabaseConfig } from '@keystone-next/keystone/types'; ``` The `db` config option configures the database used to store data in your Keystone system. @@ -131,7 +131,7 @@ The `sqlite` provider is not intended to be used in production systems, and has ## ui ```ts -import type { AdminUIConfig } from '@keystone-next/types'; +import type { AdminUIConfig } from '@keystone-next/keystone/types'; ``` The `ui` config option configures the Admin UI which is provided by Keystone. @@ -167,7 +167,8 @@ export default config({ { mode: 'write', src: ` - /* @jsx jsx */ + /** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; export default function Welcome() { return (

    Welcome to my Keystone system

    ); @@ -189,7 +190,7 @@ export default config({ ## server ``` -import type { ServerConfig } from '@keystone-next/types'; +import type { ServerConfig } from '@keystone-next/keystone/types'; ``` The `dev` and `start` commands from the Keystone [command line](../guides/cli) will start an Express web-server for you. @@ -202,6 +203,7 @@ Options: - `port` (default: `3000` ): The port your Express server will listen on. - `maxFileSize` (default: `200 * 1024 * 1024`): The maximum file size allowed for uploads. If left undefined, defaults to `200 MiB` - `healthCheck` (default: `undefined`): Allows you to configure a health check endpoint on your server. +- `extendExpressApp` (default: `undefined`): Allows you to extend the express app that Keystone creates. ```typescript export default config({ @@ -210,6 +212,7 @@ export default config({ port: 3000, maxFileSize: 200 * 1024 * 1024, healthCheck: true, + extendExpressApp: (app) => { /* ... */ }, }, /* ... */ }); @@ -227,8 +230,8 @@ config({ healthCheck: { path: '/my-health-check', data: { status: 'healthy' }, - } - } + }, + }, }) ``` @@ -244,15 +247,48 @@ config({ timestamp: Date.now(), uptime: process.uptime(), }), - } - } + }, + }, }) ``` +### extendExpressApp + +This lets you modify the express app that Keystone creates _before_ the Apollo Server and Admin UI Middleware are added to it (but after the `cors` and `healthcheck` options are applied). + +For example, you could add your own request logging middleware: + +```ts +export default config({ + server: { + extendExpressApp: (app) => { + app.use((req, res, next) => { + console.log('A request!'); + next(); + }); + }, + }, +}); +``` + +Or add a custom route handler: + +```ts +export default config({ + server: { + extendExpressApp: (app) => { + app.get('/_version', (req, res) => { + res.send('v6.0.0-rc.2'); + }); + }, + }, +}); +``` + ## session ``` -import type { SessionStrategy } from '@keystone-next/types'; +import type { SessionStrategy } from '@keystone-next/keystone/types'; ``` The `session` config option allows you to configure session management of your Keystone system. @@ -274,7 +310,7 @@ See the [Session API](./session) for more details on how to configure session ma ## graphql ``` -import type { GraphQLConfig } from '@keystone-next/types'; +import type { GraphQLConfig } from '@keystone-next/keystone/types'; ``` The `graphql` config option allows you to configures certain aspects of your GraphQL API. @@ -286,18 +322,21 @@ Options: These can be filtered out with `apolloConfig.formatError` if you need to process them, but do not want them returned over the GraphQL API. - `queryLimits` (default: `undefined`): Allows you to limit the total number of results returned from a query to your GraphQL API. See also the per-list `graphql.queryLimits` option in the [Schema API](./schema). +- `path` (default: `'/api/graphql'`): The path of the GraphQL API endpoint. - `apolloConfig` (default: `undefined`): Allows you to pass extra options into the `ApolloServer` constructor. - `playground` (default: `process.env.NODE_ENV !== 'production'`): If truthy, will enable the GraphQL Playground for testing queries and mutations in the browser. - To configure behaviour, pass an object of [GraphQL Playground settings](https://github.com/graphql/graphql-playground#settings). - - See the [Apollo docs](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor) for more supported options. + To configure behaviour, pass an object of [GraphQL Playground settings](https://github.com/graphql/graphql-playground#settings). See the [Apollo docs](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor) for more supported options. + - `introspection` (default: `undefined`): Introspection enables you to query a GraphQL server for information about the underlying schema. If the playground is enabled then introspection is automatically enabled, unless specifically disabled. ```typescript export default config({ graphql: { debug: process.env.NODE_ENV !== 'production', queryLimits: { maxTotalResults: 100 }, + path: '/api/graphql', apolloConfig: { playground: process.env.NODE_ENV !== 'production', + introspection: process.env.NODE_ENV !== 'production', /* ... */ }, }, @@ -308,7 +347,7 @@ export default config({ ## extendGraphqlSchema ``` -import type { ExtendGraphqlSchema } from '@keystone-next/types'; +import type { ExtendGraphqlSchema } from '@keystone-next/keystone/types'; ``` The `extendGraphqlSchema` config option allows you to extend the GraphQL API which is generated by Keystone based on your schema definition. @@ -317,7 +356,7 @@ It has a TypeScript type of `ExtendGraphqlSchema`. In general you will use the function `graphQLSchemaExtension({ typeDefs, resolvers })` to create your schema extension. ```typescript -import { config, graphQLSchemaExtension } from '@keystone-next/keystone/schema'; +import { config, graphQLSchemaExtension } from '@keystone-next/keystone'; export default config({ extendGraphqlSchema: graphQLSchemaExtension({ typeDefs, resolvers }), @@ -334,7 +373,7 @@ In order to use this field type you need to configure Keystone with information At the moment Keystone supports storing files on the local filesystem, and is agnostic about how files are served. ```typescript -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; export default config({ files: { @@ -362,7 +401,7 @@ In order to use this field type you need to configure Keystone with information At the moment Keystone supports storing files on the local filesystem, and is agnostic about how images are served. ```typescript -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; export default config({ images: { @@ -389,7 +428,7 @@ The following flags allow you to enable features which are still in preview. These features are not guaranteed to work, and should be used with caution. ```typescript -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; export default config({ experimental: { diff --git a/docs/pages/docs/apis/context.mdx b/docs/pages/docs/apis/context.mdx index 2c06bbda7e7..a413b2a6362 100644 --- a/docs/pages/docs/apis/context.mdx +++ b/docs/pages/docs/apis/context.mdx @@ -13,7 +13,7 @@ The APIs provided by the `KeystoneContext` object can be used to write the busin The `KeystoneContext` object has the following properties, which are documented below. ```typescript -import type { KeystoneContext } from '@keystone-next/types'; +import type { KeystoneContext } from '@keystone-next/keystone/types'; context = { // HTTP request object @@ -111,7 +111,7 @@ See the [session API](./session#session-context) for more details. When using the `context.lists`, `context.graphql.run`, and `context.graphql.raw` APIs, access control and session information is passed through to these calls from the `context` object. The following functions will create a new `KeystoneContext` object with this behaviour modified. -`sudo()`: A function which returns a new `KeystoneContext` object with all access control disabled for subsequent API calls. +`sudo()`: A function which returns a new `KeystoneContext` object with all access control disabled and all filters enabled for subsequent API calls. `exitSudo()`: A function which returns a new `KeystoneContext` object with all access control re-enabled for subsequent API calls. diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index 3f5daecb149..b8dff67d9a4 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -12,7 +12,7 @@ This document covers the different field types which are available and the confi To see how to access fields in the GraphQL API please see the [GraphQL API](./graphql) docs. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; import { // Scalar types checkbox, @@ -36,7 +36,7 @@ import { // File types file, image, -} from '@keystone-next/fields'; +} from '@keystone-next/keystone/fields'; // Complex types import { document } from '@keystone-next/fields-document'; @@ -63,6 +63,8 @@ All options are optional. Options: +- `isFilterable` (default: `false`): If `true`, the GraphQL API and Admin UI will support filtering by this field. +- `isOrderable` (default: `false`): If `true`, the GraphQL API and Admin UI will support ordering by this field. - `access`: Defines the [Access Control](../guides/access-control) rules for the field. See the [Access Control API](./access-control) for full details on the available access control options. - `hooks`: The `hooks` option defines [hook](../guides/hooks) functions for the field. @@ -85,6 +87,10 @@ Options: See the [Schema API](./schema#ui) for details. - `graphql`: Configures certain aspects of the GraphQL API. - `cacheHint` (default: `undefined`): Allows you to specific the [dynamic cache control hints](https://www.apollographql.com/docs/apollo-server/performance/caching/#in-your-resolvers-dynamic) used for queries to this this list. + - `omit` (default: 'undefined'): Controls whether this field appears in the autogenerated types of the GraphQL API + This option accepts either `true`, or an array of the values `read`, `create`, or `update`. + If you specify `true` then the field will be excluded from all input and output types in the GraphQL API. + If you provide an array of `read`, `create`, or `update` the field will be omitted from the corresponding input and output types in the GraphQL API. ```typescript export default config({ @@ -92,6 +98,8 @@ export default config({ ListName: list({ fields: { fieldName: text({ + isFilterable: true, + isOrderable: true, access: { /* ... */ }, hooks: { /* ... */ }, label: '...', @@ -108,7 +116,8 @@ export default config({ }, }, graphql: { - cacheHint: { maxAge: 60, scope: CacheScope.Private } + cacheHint: { maxAge: 60, scope: CacheScope.Private }, + omit: ['read', 'create', 'update'], } }), /* ... */ @@ -135,8 +144,8 @@ Options: - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { checkbox } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -166,11 +175,13 @@ Options: `context` is a [`KeystoneContext`](./context) object. `originalInput` is an object containing the data passed in to the `create` mutation. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. -- `isUnique` (default: `false`): If `true` then all values of this field must be unique. This will also allow you to uniquely filter by this field in the GraphQL API. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { integer } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { integer } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -179,7 +190,7 @@ export default config({ fieldName: integer({ defaultValue: 0, isRequired: true, - isUnique: true, + isIndexed: 'unique', }), /* ... */ }, @@ -198,8 +209,8 @@ Currently the `json` field is non-orderable and non-filterable. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { json } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { json } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -228,11 +239,13 @@ Options: `context` is a [`KeystoneContext`](./context) object. `originalInput` is an object containing the data passed in to the `create` mutation. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. -- `isUnique` (default: `false`): If `true` then all values of this field must be unique. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { float } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { float } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -241,7 +254,7 @@ export default config({ fieldName: float({ defaultValue: 3.14159, isRequired: true, - isUnique: true, + isIndexed: 'unique', }), /* ... */ }, @@ -265,11 +278,13 @@ Options: - `precision` (default: `18`): Maximum number of digits that are present in the number. - `scale` (default: `4`): Maximum number of decimal places. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. -- `isUnique` (default: `false`): If `true` then all values of this field must be unique. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { decimal } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { decimal } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -280,7 +295,7 @@ export default config({ precision: 12, scale: 3, isRequired: true, - isUnique: true, + isIndexed: 'unique', }), /* ... */ }, @@ -304,8 +319,8 @@ Options: This module will be used for all encryption routines in the `password` field. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { password } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { password } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -345,13 +360,15 @@ Options: `context` is a [`KeystoneContext`](./context) object. `originalInput` is an object containing the data passed in to the `create` mutation. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. -- `isUnique` (default: `false`): If `true` then all values of this field must be unique. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. - `ui` (default: `{ displayMode: 'select' }`): Configures the display mode of the field in the Admin UI. Can be one of `['select', 'segmented-control']`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { select } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { select } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -365,7 +382,7 @@ export default config({ ], defaultValue: '...', isRequired: true, - isUnique: true, + isIndexed: 'unique', ui: { displayMode: 'select' }, }), /* ... */ @@ -388,13 +405,15 @@ Options: `context` is a [`KeystoneContext`](./context) object. `originalInput` is an object containing the data passed in to the `create` mutation. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. -- `isUnique` (default: `false`): If `true` then all values of this field must be unique. This will also allow you to uniquely filter by this field in the GraphQL API. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. - `ui` (default: `{ displayMode: 'input' }`): Configures the display mode of the field in the Admin UI. Can be one of `['input', 'textarea']`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -403,7 +422,7 @@ export default config({ fieldName: text({ defaultValue: '...', isRequired: true, - isUnique: true, + isIndexed: 'unique', ui: { displayMode: 'textarea' }, }), /* ... */ @@ -427,11 +446,13 @@ Options: `context` is a [`KeystoneContext`](./context) object. `originalInput` is an object containing the data passed in to the `create` mutation. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. -- `isUnique` (default: `false`): If `true` then all values of this field must be unique. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { timestamp } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { timestamp } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -440,7 +461,7 @@ export default config({ fieldName: timestamp({ defaultValue: '1970-01-01T00:00:00.000Z', isRequired: true, - isUnique: true, + isIndexed: 'unique', }), /* ... */ }, @@ -459,7 +480,7 @@ A `relationship` field represents a relationship between two lists. Read our [relationships guide](../guides/relationships) for details on Keystone’s relationship model and how to configure them in your project. -- `ref` (required): A string of the form `` or `.`. +- `ref` (required): A string of the form `` or `.`. - `many` (default: `false`): Configures the cardinality of the relationship. - `defaultValue` (default: `undefined`): Can be either a relationship input value `{ connect: { id: ID } }` or an async function which takes an argument `({ context, originalInput })` and returns a relationship input value. This value will be used for the field when creating items if no explicit value is set. @@ -480,8 +501,8 @@ Read our [relationships guide](../guides/relationships) for details on Keystone - `ui.displayMode === 'count'` only supports `many` relationships ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { relationship } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { relationship } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -528,11 +549,11 @@ Options: - `defaultValue` - `isRequired` -- `isUnique` +- `isIndexed` ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { autoIncrement } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { autoIncrement } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -541,7 +562,7 @@ export default config({ fieldName: autoIncrement({ defaultValue: 0, isRequired: true, - isUnique: true, + isIndexed: 'unique', }), /* ... */ }, @@ -565,18 +586,17 @@ Options: - `graphQLReturnFragment` (default: `''` ): The sub-fields that should be fetched by the Admin UI when displaying this field. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { virtual } from '@keystone-next/fields'; -import { schema } from '@keystone-next/types'; +import { config, createSchema, list, graphql } from '@keystone-next/keystone'; +import { virtual } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ ListName: list({ fields: { fieldName: virtual({ - field: schema.field({ - type: schema.String, - args: { something: schema.arg({ type: schema.Int }) }, + field: graphql.field({ + type: graphql.String, + args: { something: graphql.arg({ type: graphql.Int }) }, resolve(item, args, context, info) { } @@ -606,8 +626,8 @@ Options: - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { file } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { file } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -636,8 +656,8 @@ Options: - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { image } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { image } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -671,7 +691,7 @@ Options: - `layouts` ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export default config({ @@ -710,7 +730,7 @@ export default config({ - `folder` ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; import { cloudinaryImage } from '@keystone-next/cloudinary'; export default config({ diff --git a/docs/pages/docs/apis/filters.mdx b/docs/pages/docs/apis/filters.mdx index dabc8c8c8c9..2b4944c726e 100644 --- a/docs/pages/docs/apis/filters.mdx +++ b/docs/pages/docs/apis/filters.mdx @@ -10,6 +10,8 @@ Each field type provides its own set of filters which can be used with [queries] This page lists all the filters available for each field type. For more details on how to use filters in queries please consult to the [GraphQL Queries - Filters](../guides/filters) guide. +?> Filters are disabled by default as a security precaution. To enable the filters on a field, set the config option `{ isFilterable: true }`. + ## Scalar types ### checkbox diff --git a/docs/pages/docs/apis/graphql.mdx b/docs/pages/docs/apis/graphql.mdx index f4ef99a7344..7c656647d72 100644 --- a/docs/pages/docs/apis/graphql.mdx +++ b/docs/pages/docs/apis/graphql.mdx @@ -12,12 +12,12 @@ Keystone generates a CRUD (create, read, update, delete) GraphQL API based on th Consider the following system definition: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ - User: list({ fields: { name: text() } }), + User: list({ fields: { name: text({ isOrderable: true }) } }), }), /* ... */ }); diff --git a/docs/pages/docs/apis/hooks.mdx b/docs/pages/docs/apis/hooks.mdx index 3241396d799..c53f12b5bdd 100644 --- a/docs/pages/docs/apis/hooks.mdx +++ b/docs/pages/docs/apis/hooks.mdx @@ -15,8 +15,8 @@ All hook functions are async and, with the exception of `resolveInput`, do not r For examples of how to use hooks in your system please see the [hooks guide](../guides/hooks). ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -72,7 +72,7 @@ The result of `resolveInput` will be passed as `resolvedData` into the next stag | Argument | Description | | :-------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'create'` or `'update'`). | | `originalInput` | The value of `data` passed into the mutation. | | `existingItem` | The currently stored item (`undefined` for `create` operations). This object is an unresolved list item. [list item API](./list-items) for more details on unresolved list items. | @@ -80,8 +80,8 @@ The result of `resolveInput` will be passed as `resolvedData` into the next stag | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -104,7 +104,7 @@ export default config({ hooks: { resolveInput: async ({ listKey, - fieldPath, + fieldKey, operation, originalInput, existingItem, @@ -134,7 +134,7 @@ These error messages will be returned as a `ValidationFailureError` from the Gra | Argument | Description | | :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'create'` or `'update'`). | | `originalInput` | The value of `data` passed into the mutation. | | `existingItem` | The current value of the item being updated (`undefined` for `create` operations). This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | @@ -143,8 +143,8 @@ These error messages will be returned as a `ValidationFailureError` from the Gra | `addValidationError(msg)` | Used to set a validation error. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -165,7 +165,7 @@ export default config({ hooks: { validateInput: async ({ listKey, - fieldPath, + fieldKey, operation, originalInput, existingItem, @@ -190,7 +190,7 @@ It is invoked after all `validateInput` hooks have been run, but before the data | Argument | Description | | :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'create'` or `'update'`). | | `originalInput` | The value of `data` passed into the mutation. | | `existingItem` | The current value of the item being updated (`undefined` for `create` operations). This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | @@ -198,8 +198,8 @@ It is invoked after all `validateInput` hooks have been run, but before the data | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -219,7 +219,7 @@ export default config({ hooks: { beforeChange: async ({ listKey, - fieldPath, + fieldKey, operation, originalInput, existingItem, @@ -241,7 +241,7 @@ The `afterChange` function is used to perform side effects after the data for a | Argument | Description | | :-------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'create'` or `'update'`). | | `originalInput` | The value of `data` passed into the mutation. | | `existingItem` | The previous value of the item being updated (`undefined` for `create` operations). This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | @@ -249,8 +249,8 @@ The `afterChange` function is used to perform side effects after the data for a | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -270,7 +270,7 @@ export default config({ hooks: { afterChange: async ({ listKey, - fieldPath, + fieldKey, operation, originalInput, existingItem, @@ -302,15 +302,15 @@ These error messages will be returned as a `ValidationFailureError` from the Gra | Argument | Description | | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'delete'`). | | `existingItem` | The value of the item to be deleted. This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | | `addValidationError(msg)` | Used to set a validation error. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -329,7 +329,7 @@ export default config({ hooks: { validateDelete: async ({ listKey, - fieldPath, + fieldKey, operation, existingItem, context, @@ -352,14 +352,14 @@ It is invoked after all `validateDelete` hooks have been run. | Argument | Description | | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'delete'`). | | `existingItem` | The value of the item to be deleted. This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -372,7 +372,7 @@ export default config({ fields: { fieldName: text({ hooks: { - beforeDelete: async ({ listKey, fieldPath, operation, existingItem, context }) => { + beforeDelete: async ({ listKey, fieldKey, operation, existingItem, context }) => { /* ... */ }, }, @@ -390,14 +390,14 @@ The `afterDelete` function is used to perform side effects after the data for a | Argument | Description | | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `listKey` | The key of the list being operated on. | -| `fieldPath` | The path of the field being operated on (field hooks only). | +| `fieldKey` | The key of the field being operated on (field hooks only). | | `operation` | The operation being performed (`'delete'`). | | `existingItem` | The value of the item, now deleted. This object is an unresolved list item. See the [list item API](./list-items) for more details on unresolved list items. | | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -410,7 +410,7 @@ export default config({ fields: { fieldName: text({ hooks: { - afterDelete: async ({ listKey, fieldPath, operation, existingItem, context }) => { + afterDelete: async ({ listKey, fieldKey, operation, existingItem, context }) => { /* ... */ }, }, diff --git a/docs/pages/docs/apis/index.tsx b/docs/pages/docs/apis/index.tsx index a390f1e5ec7..c8e2baccf97 100644 --- a/docs/pages/docs/apis/index.tsx +++ b/docs/pages/docs/apis/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/pages/docs/apis/schema.mdx b/docs/pages/docs/apis/schema.mdx index 8b09c020d83..590deca6433 100644 --- a/docs/pages/docs/apis/schema.mdx +++ b/docs/pages/docs/apis/schema.mdx @@ -9,7 +9,7 @@ To setup the `lists` property of the system configuration you need to use the `c This function accepts an object with list names as keys, and `list()` configurations as values. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; export default config({ lists: createSchema({ @@ -21,6 +21,8 @@ export default config({ graphql: { /* ... */ }, db: { /* ... */ }, description: '...', + defaultIsFilterable: true, + defaultIsOrderable: true, }), /* ... */ }), @@ -30,14 +32,19 @@ export default config({ This document will explain the configuration options which can be used with the `list()` function. +Options: + +- `defaultIsFilterable`: If `true`, all fields will be filterable by default. They can override this by setting the field level `isFilterable` option to `false`. +- `defaultIsOrderable`: If `true`, all fields will be orderable by default. They can override this by setting the field level `isOrderable` option to `false`. + ## fields The `fields` option defines the names, types, and configuration of the fields in the list. This configuration option takes an object with field names as keys, and configured field types as values. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -102,8 +109,8 @@ Options: - `pageSize` (default: `50`): Sets the number of items to show per page in the list view. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields`; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields`; export default config({ lists: createSchema({ @@ -155,10 +162,14 @@ Options: - `queryLimits` (default: `undefined`): Allows you to limit the number of results returned from a query to this list in the GraphQL API. See also the global `graphql.queryLimits` option in the [System Configuration API](./config). - `cacheHint` (default: `undefined`): Allows you to specific the [dynamic cache control hints](https://www.apollographql.com/docs/apollo-server/performance/caching/#in-your-resolvers-dynamic) used for queries to this this list. +- `omit` (default: `undefined`): Allows you to configure which parts of the CRUD API are autogenerated for your GraphQL API. + This option accepts either `true`, or an array of the values `query`, `create`, `update`, or `delete`. + If you specify `true` then the entire list, including its output type, will be omitted from the GraphQL API. + If you provide an array of `query`, `create`, `update`, or `delete` options, the corresponding operations will be omitted from the GraphQL API. ```typescript import { CacheScope } from 'apollo-cache-control'; -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; export default config({ lists: createSchema({ @@ -168,7 +179,8 @@ export default config({ itemQueryName: '...', listQueryName: '...', queryLimits: { maxResults: 100 }, - cacheHint: { maxAge: 60, scope: CacheScope.Private } + cacheHint: { maxAge: 60, scope: CacheScope.Private }, + omit: ['query', 'create', 'update', 'delete'], }, /* ... */ }), @@ -188,7 +200,7 @@ Options: The default across all lists can be changed at the root-level `db.idField` config. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; export default config({ lists: createSchema({ diff --git a/docs/pages/docs/apis/session.mdx b/docs/pages/docs/apis/session.mdx index 69073de4586..b860e00e9aa 100644 --- a/docs/pages/docs/apis/session.mdx +++ b/docs/pages/docs/apis/session.mdx @@ -9,7 +9,7 @@ It has a TypeScript type of `SessionStrategy`. In general you will use `SessionStrategy` objects from the `@keystone-next/keystone/session` package, rather than writing this yourself. ```typescript -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; export default config({ @@ -37,7 +37,7 @@ Both `statelessSessions()` and `storedSessions()` accept a common set of argumen `storedSessions()` accepts an additional `store` argument, which is an object capable of loading and storing session data. ```typescript -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions, storedSessions } from '@keystone-next/keystone/session'; export default config({ @@ -101,7 +101,7 @@ Keystone provides a [Redis](https://redis.io/) based session store in the packag ```typescript import redis from 'redis'; import { redisSessionStore } from '@keystone-next/session-store-redis'; -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { storedSessions } from '@keystone-next/keystone/session'; export default config({ diff --git a/docs/pages/docs/examples.tsx b/docs/pages/docs/examples.tsx index b74b068fc9a..a834368892d 100644 --- a/docs/pages/docs/examples.tsx +++ b/docs/pages/docs/examples.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/pages/docs/guides/cli.mdx b/docs/pages/docs/guides/cli.mdx index 53ceebb1db0..4419dcac954 100644 --- a/docs/pages/docs/guides/cli.mdx +++ b/docs/pages/docs/guides/cli.mdx @@ -21,7 +21,7 @@ Commands prisma run Prisma CLI commands safely ``` -!> All the commands expect to find a module called `keystone.js` (or `.ts`) with a default export that returns a Keystone System `config()` from `@keystone-next/keystone/schema`. See [System Configuration](../apis/config) for details. +!> All the commands expect to find a module called `keystone.js` (or `.ts`) with a default export that returns a Keystone System `config()` from `@keystone-next/keystone`. See [System Configuration](../apis/config) for details. ## Setting up package.json diff --git a/docs/pages/docs/guides/custom-admin-ui-logo.mdx b/docs/pages/docs/guides/custom-admin-ui-logo.mdx index e363a2cec0c..02b5f77d2af 100644 --- a/docs/pages/docs/guides/custom-admin-ui-logo.mdx +++ b/docs/pages/docs/guides/custom-admin-ui-logo.mdx @@ -29,6 +29,7 @@ If you have styling constraints, we recommend using the jsx export from the `@ke ```tsx // admin/config.tsx /** @jsxRuntime classic */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/docs/pages/docs/guides/custom-admin-ui-navigation.mdx b/docs/pages/docs/guides/custom-admin-ui-navigation.mdx index 2afc212c67f..56482dcfcfe 100644 --- a/docs/pages/docs/guides/custom-admin-ui-navigation.mdx +++ b/docs/pages/docs/guides/custom-admin-ui-navigation.mdx @@ -17,7 +17,7 @@ Reference your custom Navigation component in the export as so. ```ts // /admin/config.ts -import type { AdminConfig } from '@keystone-next/types'; +import type { AdminConfig } from '@keystone-next/keystone/types'; import { CustomNavigation } from './components/CustomNavigation'; export const components: AdminConfig['components'] = { @@ -150,7 +150,7 @@ export function CustomNavigation({ authenticatedItem, lists }: NavigationProps) // admin/config.ts -import { AdminConfig } from '@keystone-next/types'; +import { AdminConfig } from '@keystone-next/keystone/types'; import { CustomNavigation } from './components/CustomNavigation'; export const components: AdminConfig['components'] = { Navigation: CustomNavigation diff --git a/docs/pages/docs/guides/custom-admin-ui-pages.mdx b/docs/pages/docs/guides/custom-admin-ui-pages.mdx index 1bb1b559ae8..587241c0a8b 100644 --- a/docs/pages/docs/guides/custom-admin-ui-pages.mdx +++ b/docs/pages/docs/guides/custom-admin-ui-pages.mdx @@ -90,7 +90,7 @@ First add the following files to the `/admin` directory in the root of your Keys ```tsx // admin/config.ts -import type { AdminConfig } from '@keystone-next/types'; +import type { AdminConfig } from '@keystone-next/keystone/types'; import { CustomNavigation } from './components/CustomNavigation'; export const components: AdminConfig['components']= { Navigation: CustomNavigation @@ -147,6 +147,7 @@ The snippet below uses the emotion `jsx` runtime exported from `@keystone-ui/cor ```tsx // admin/pages/custom-page.tsx /** @jsxRuntime classic */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/docs/pages/docs/guides/custom-fields.mdx b/docs/pages/docs/guides/custom-fields.mdx index ade3bf42fe2..beea360b0f8 100644 --- a/docs/pages/docs/guides/custom-fields.mdx +++ b/docs/pages/docs/guides/custom-fields.mdx @@ -29,24 +29,22 @@ import { FieldTypeFunc, CommonFieldConfig, fieldType, - schema, + graphql, orderDirectionEnum, filters, FieldDefaultValue, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; export type MyIntFieldConfig = CommonFieldConfig & { defaultValue?: FieldDefaultValue; isRequired?: boolean; - isIndexed?: boolean; - isUnique?: boolean; + isIndexed?: boolean | 'unique'; }; export const myInt = ({ isIndexed, - isUnique, isRequired, defaultValue, ...config @@ -56,16 +54,16 @@ export const myInt = kind: 'scalar', mode: 'optional', scalar: 'Int', - index: isIndexed ? 'index' : isUnique ? 'unique' : undefined, + index: isIndexed === true ? 'index' : isIndexed || undefined, })({ ...config, input: { - where: { arg: schema.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, - create: { arg: schema.arg({ type: schema.Int }) }, - update: { arg: schema.arg({ type: schema.Int }) }, - orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, + where: { arg: graphql.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, + create: { arg: graphql.arg({ type: graphql.Int }) }, + update: { arg: graphql.arg({ type: graphql.Int }) }, + orderBy: { arg: graphql.arg({ type: orderDirectionEnum }) }, }, - output: schema.field({ type: schema.Int }), + output: graphql.field({ type: graphql.Int }), views: require.resolve('./view.tsx'), __legacy: { isRequired, @@ -85,10 +83,10 @@ The `input` object defines the GraphQL inputs for the field type. ```ts input: { - where: { arg: schema.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, - create: { arg: schema.arg({ type: schema.Int }) }, - update: { arg: schema.arg({ type: schema.Int }) }, - orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, + where: { arg: graphql.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, + create: { arg: graphql.arg({ type: graphql.Int }) }, + update: { arg: graphql.arg({ type: graphql.Int }) }, + orderBy: { arg: graphql.arg({ type: orderDirectionEnum }) }, }, ``` @@ -96,10 +94,10 @@ You can also provide resolvers to transform the value coming from GraphQL into t ```ts input: { - where: { arg: schema.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, - create: { arg: schema.arg({ type: schema.Int }), resolve: (val, context) => val }, - update: { arg: schema.arg({ type: schema.Int }), resolve: (val, context) => val }, - orderBy: { arg: schema.arg({ type: orderDirectionEnum }), resolve: (val, context) => val }, + where: { arg: graphql.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon }, + create: { arg: graphql.arg({ type: graphql.Int }), resolve: (val, context) => val }, + update: { arg: graphql.arg({ type: graphql.Int }), resolve: (val, context) => val }, + orderBy: { arg: graphql.arg({ type: orderDirectionEnum }), resolve: (val, context) => val }, }, ``` @@ -108,14 +106,14 @@ input: { The output field defines what can be fetched from the field: ```ts -output: schema.field({ type: schema.Int }) +output: graphql.field({ type: graphql.Int }) ``` A resolver can also be provided: ```ts -output: schema.field({ - type: schema.Int, +output: graphql.field({ + type: graphql.Int, resolve({ value, item }, args, context, info) { return value; } @@ -164,7 +162,7 @@ The `Field` export is a React component which is used in the **item view** and t // view.tsx import { FieldContainer, FieldLabel, TextInput } from '@keystone-ui/fields'; -import { FieldProps } from '@keystone-next/types'; +import { FieldProps } from '@keystone-next/keystone/types'; export const Field = ({ field, value, onChange, autoFocus }: FieldProps) => ( @@ -195,7 +193,7 @@ Note it does not allow modifying the value. // view.tsx import { CellLink, CellContainer } from '@keystone-next/keystone/admin-ui/components'; -import { CellComponent } from '@keystone-next/types'; +import { CellComponent } from '@keystone-next/keystone/types'; export const Cell: CellComponent = ({ item, field, linkTo }) => { let value = item[field.path] + ''; @@ -213,7 +211,7 @@ Note it does not allow modifying the value. // view.tsx import { FieldContainer, FieldLabel } from '@keystone-ui/fields'; -import { CardValueComponent } from '@keystone-next/types'; +import { CardValueComponent } from '@keystone-next/keystone/types'; export const CardValue: CardValueComponent = ({ item, field }) => { return ( diff --git a/docs/pages/docs/guides/document-fields.mdx b/docs/pages/docs/guides/document-fields.mdx index 664a7f01ae6..e5de0fcd824 100644 --- a/docs/pages/docs/guides/document-fields.mdx +++ b/docs/pages/docs/guides/document-fields.mdx @@ -22,7 +22,7 @@ The document field provides a number of different formatting options, all of whi To get started with a fully featured editor experience, you can turn on all of the built-in options. ```typescript -import { createSchema, list } from '@keystone-next/keystone/schema'; +import { createSchema, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export const lists = createSchema({ @@ -161,9 +161,9 @@ For example, you might want to include twitter-style mentions of other users in We can achieve this with the `relationships` option to the document field. ```tsx -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; -import { text } from '@keystone-next/fields'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -352,7 +352,7 @@ You need to import the `componentBlocks` and pass it to the document field along `keystone.ts` ```ts -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; import { componentBlocks } from './component-blocks'; @@ -571,7 +571,7 @@ fields.object({ To use relationship fields on component blocks, you need to add a relationship to the document field config. ```tsx -import { config, createSchema, list } from '@keystone-next/keystone/schema'; +import { config, createSchema, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export default config({ diff --git a/docs/pages/docs/guides/filters.mdx b/docs/pages/docs/guides/filters.mdx index bca50788605..e9de537e1da 100644 --- a/docs/pages/docs/guides/filters.mdx +++ b/docs/pages/docs/guides/filters.mdx @@ -12,6 +12,8 @@ This guide will show you how to use filters to get data you need. !> The filter references in this guide are based on the schema defined in the [Task Manager](https://github.com/keystonejs/keystone/tree/master/examples/task-manager) example project. +?> Filters are disabled by default as a security precaution. To enable the filters on a field, set the config option `{ isFilterable: true }`. + ## Scalar Filters If we want to find all the `Tasks` in our system, we can use the query `tasks()`. diff --git a/docs/pages/docs/guides/hooks.mdx b/docs/pages/docs/guides/hooks.mdx index 5efc910c478..67eab162ac9 100644 --- a/docs/pages/docs/guides/hooks.mdx +++ b/docs/pages/docs/guides/hooks.mdx @@ -16,8 +16,8 @@ A hook is a function you define as part of your [schema configuration](../apis/s Let's look at a basic example to log a message to the console whenever a new user is created. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -54,8 +54,8 @@ The `resolveInput` hook lets us take the data which has been provided to the Gra Let's write a hook which takes the data for a blog post and converts the first letter to upper-case. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -101,8 +101,8 @@ An empty string, `""`, is a perfectly valid `String` value to pass into GraphQL. Let's use a validation hook to ensure that this value doesn't make it into our database. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -145,8 +145,8 @@ We can use the `beforeChange` and `afterChange` hooks to do this. Let's send an email after a user is created. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; // Keystone leaves it up to you to decide how best to implement email in your system import { sendWelcomeEmail } from './lib/welcomeEmail'; @@ -191,15 +191,15 @@ Similary, the `beforeDelete` and `afterDelete` hooks can be used to trigger side All of the examples above have involved hooks associated with a particular list. Keystone also supports setting of hooks associated with a particular field. -All the same hooks are available, and they receive all the same arguments, along with an extra `fieldPath` argument. +All the same hooks are available, and they receive all the same arguments, along with an extra `fieldKey` argument. Field hooks can be useful if you want to have field specific rules. For example, you might have an email validation function which want to use in your system. You could always write this as a list hook, but it will make your code more clear if you write this as a field hook. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -208,10 +208,10 @@ export default config({ name: text(), email: text({ hooks: { - validateInput: ({ addValidationError, resolvedData, fieldPath }) => { - const email = resolvedData[fieldPath]; + validateInput: ({ addValidationError, resolvedData, fieldKey }) => { + const email = resolvedData[fieldKey]; if (email !== undefined && email !== null && !email.includes('@')) { - addValidationError(`The email address ${email} provided for the field ${fieldPath} must contain an '@' character`); + addValidationError(`The email address ${email} provided for the field ${fieldKey} must contain an '@' character`); } }, }, diff --git a/docs/pages/docs/guides/index.tsx b/docs/pages/docs/guides/index.tsx index 826749e0580..ab9cb416088 100644 --- a/docs/pages/docs/guides/index.tsx +++ b/docs/pages/docs/guides/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/pages/docs/guides/relationships.mdx b/docs/pages/docs/guides/relationships.mdx index 6d546873fc1..09ce5b98126 100644 --- a/docs/pages/docs/guides/relationships.mdx +++ b/docs/pages/docs/guides/relationships.mdx @@ -28,8 +28,8 @@ These topics are easier to understand by example. We’ll explore them, as well Relationships are made using the [`relationship`](../apis/fields#relationship) field type within a [`list()`](../apis/schema). In our blog example we can connect a blog `post` to some `users` using the relationship field’s `ref` configuration option like so: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text, relationship } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -72,8 +72,8 @@ query { If we can find all the `authors` of a post, we can also find all the posts written by a particular user. To do this we need to configure a two-sided relationship in our schema: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text, relationship } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -121,8 +121,8 @@ query { Keystone also lets you define one, and two-sided **relationships that refer to the same list**. To make a _one-sided_ Twitter style following relationship we do the following: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text, relationship } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -139,8 +139,8 @@ export default config({ Or change this into a _two-sided_ relationship to also access the followers of every user: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text, relationship } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ @@ -184,8 +184,8 @@ Let’s explore how to set up each type of cardinality in the context of our blo - Users can have multiple posts ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { text, relationship } from '@keystone-next/fields'; +import { config, createSchema, list } from '@keystone-next/keystone'; +import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ diff --git a/docs/pages/docs/guides/testing.mdx b/docs/pages/docs/guides/testing.mdx index ae34ac045b6..325010c37da 100644 --- a/docs/pages/docs/guides/testing.mdx +++ b/docs/pages/docs/guides/testing.mdx @@ -6,11 +6,11 @@ import { InlineCode } from '../../../components/primitives/Code'; # Testing When building a web application it's important to be able to test the behaviour of your system to ensure it does what you expect. -In this guide we'll show you how to use the `@keystone-next/testing` package and [Jest](https://jestjs.io/) to write tests to check the behaviour of your GraphQL API. +In this guide we'll show you how to use `@keystone-next/keystone/testing` and [Jest](https://jestjs.io/) to write tests to check the behaviour of your GraphQL API. ## Running tests -In order to run tests using the `@keystone-next/testing` package, we recommend adding the following script to your `package.json` file. +In order to run tests using `@keystone-next/keystone/testing`, we recommend adding the following script to your `package.json` file. ```json "scripts": { @@ -33,7 +33,7 @@ The first step to writing a test for your Keystone system is to setup a test run You can then use this runner to wrap your test functions. ```typescript -import { setupTestRunner } from '@keystone-next/testing'; +import { setupTestRunner } from '@keystone-next/keystone/testing'; import { config } from './keystone'; const runner = setupTestRunner({ config }); @@ -207,8 +207,8 @@ The context API can be used after calling `connect()` in the `beforeAll()` block x> Be careful of sharing database state across tests. Avoid relying on changes of state from one test in subsequent tests. ``` -import { setupTestEnv, TestEnv } from '@keystone-next/testing'; -import { KeystoneContext } from '@keystone-next/types'; +import { setupTestEnv, TestEnv } from '@keystone-next/keystone/testing'; +import { KeystoneContext } from '@keystone-next/keystone/types'; describe('Example tests using test environment', () => { let testEnv: TestEnv; diff --git a/docs/pages/docs/guides/virtual-fields.mdx b/docs/pages/docs/guides/virtual-fields.mdx index 270c279b887..7d7f14f6f61 100644 --- a/docs/pages/docs/guides/virtual-fields.mdx +++ b/docs/pages/docs/guides/virtual-fields.mdx @@ -18,17 +18,16 @@ In this guide we'll introduce the syntax for adding virtual fields, and show how We'll start with a list called `Example` and create a virtual field called `hello`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone/schema'; -import { virtual } from '@keystone-next/fields'; -import { schema } from '@keystone-next/types'; +import { config, createSchema, list, graphql } from '@keystone-next/keystone'; +import { virtual } from '@keystone-next/keystone/fields'; export default config({ lists: createSchema({ Example: list({ fields: { hello: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, resolve() { return "Hello, world!"; }, @@ -59,18 +58,18 @@ which gives the response: The value of `hello` is generated from the `resolve` function, which returns the string `"Hello, world!"`. -## The schema API +## The `graphql` API -The `virtual` field is configured using functions from the `schema` API in the `@keystone-next/types` package. +The `virtual` field is configured using functions from the `graphql` export from `@keystone-next/keystone`. This API provides the interface required to create type-safe extensions to the Keystone GraphQL schema. -The schema API is based on the [`@graphql-ts/schema`](https://github.com/Thinkmill/graphql-ts) package. +The `graphql` API is based on the [`@graphql-ts/schema`](https://github.com/Thinkmill/graphql-ts) package. -The `virtual` field accepts a configuration option called `field`, which is a `schema.field()` object. +The `virtual` field accepts a configuration option called `field`, which is a `graphql.field()` object. -In our example we passed in two required options to `schema.field()`. -The option `type: schema.String` specifies the GraphQL type of our virtual field, and `resolve() { ... }` defines the [GraphQL resolver](https://graphql.org/learn/execution/#root-fields-resolvers) to be executed when this field is queried. +In our example we passed in two required options to `graphql.field()`. +The option `type: graphql.String` specifies the GraphQL type of our virtual field, and `resolve() { ... }` defines the [GraphQL resolver](https://graphql.org/learn/execution/#root-fields-resolvers) to be executed when this field is queried. -The `schema` API provides support for the built in GraphQL scalar types `Int`, `Float`, `String`, `Boolean`, and `ID`, as well as the Keystone custom scalars `Upload` and `JSON`. +The `graphql` API provides support for the built in GraphQL scalar types `Int`, `Float`, `String`, `Boolean`, and `ID`, as well as the Keystone custom scalars `Upload` and `JSON`. ## Resolver arguments @@ -94,8 +93,8 @@ export default config({ content: text(), author: relationship({ ref: 'Author', many: false }), authorName: virtual({ - type: schema.String, - field: schema.field({ + type: graphql.String, + field: graphql.field({ async resolve(item, args, context) { const { author } = await context.lists.Post.findOne({ where: { id: item.id.toString() }, @@ -132,11 +131,11 @@ export default config({ fields: { content: text(), excerpt: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, args: { - length: schema.arg({ - type: schema.nonNull(schema.Int), + length: graphql.arg({ + type: graphql.nonNull(graphql.Int), defaultValue: 200 }), }, @@ -190,7 +189,7 @@ Had we not specified `defaultValue` in our field, the `graphQLReturnFragment` ar The examples above returned a scalar `String` value. Virtual fields can also be configured to return a GraphQL object. In our blog example we might want to provide some statistics on each blog post, such as the number of words, sentences, and paragraphs in the post. -We can set up a GraphQL type called `PostCounts` to represent this data using the `schema.object()` function. +We can set up a GraphQL type called `PostCounts` to represent this data using the `graphql.object()` function. ```typescript export default config({ @@ -199,17 +198,17 @@ export default config({ fields: { content: text(), counts: virtual({ - field: schema.field({ - type: schema.object<{ + field: graphql.field({ + type: graphql.object<{ words: number; sentences: number; paragraphs: number; }>()({ name: 'PostCounts', fields: { - words: schema.field({ type: schema.Int }), - sentences: schema.field({ type: schema.Int }), - paragraphs: schema.field({ type: schema.Int }), + words: graphql.field({ type: graphql.Int }), + sentences: graphql.field({ type: graphql.Int }), + paragraphs: graphql.field({ type: graphql.Int }), }, }), resolve(item: any) { @@ -237,18 +236,18 @@ This fragment tells the Keystone Admin UI which values to show in the item page #### Self-referencing objects -!> This information is specifically for TypeScript users of the `schema.object()` function with a self-referential GraphQL type. +!> This information is specifically for TypeScript users of the `graphql.object()` function with a self-referential GraphQL type. -GraphQL types will often contain references to themselves and to make TypeScript allow that, you need have an explicit type annotation of `schema.ObjectType` along with making `fields` a function that returns the object. +GraphQL types will often contain references to themselves and to make TypeScript allow that, you need have an explicit type annotation of `graphql.ObjectType` along with making `fields` a function that returns the object. ```ts type PersonRootVal = { name: string; friends: PersonRootVal[] }; -const Person: schema.ObjectType = schema.object()({ +const Person: graphql.ObjectType = graphql.object()({ name: "Person", fields: () => ({ - name: schema.field({ type: schema.String }), - friends: schema.field({ type: schema.list(Person) }), + name: graphql.field({ type: graphql.String }), + friends: graphql.field({ type: graphql.list(Person) }), }), }); ``` @@ -258,11 +257,11 @@ const Person: schema.ObjectType = schema.object()( Rather than returning a custom GraphQL object, we might want to have a virtual field which returns one of the GraphQL types generated by Keystone itself. For example, for each `Author` we might want to return their `latestPost` as a `Post` object. -To achieve this, rather than passing in `schema.field({ ... })` as the `field` option, we pass in a function `lists => schema.field({ ... })`. +To achieve this, rather than passing in `graphql.field({ ... })` as the `field` option, we pass in a function `lists => graphql.field({ ... })`. The argument `lists` contains the type information for all of the Keystone lists. In our case, we want the output type of the `Post` list, so we specify `type: lists.Post.types.output`. -``` +```ts export const lists = createSchema({ Post: list({ fields: { @@ -275,11 +274,11 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), latestPost: virtual({ field: lists => - schema.field({ + graphql.field({ type: lists.Post.types.output, async resolve(item, args, context) { const { posts } = await context.lists.Author.findOne({ diff --git a/docs/pages/docs/index.tsx b/docs/pages/docs/index.tsx index 39194cd9177..e206ee6579e 100644 --- a/docs/pages/docs/index.tsx +++ b/docs/pages/docs/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; import Link from 'next/link'; @@ -71,7 +72,7 @@ export default function Docs() { frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen - > + />

    mwf$eFVzvD?Qm zaL$v|tJDKSPjLSxFp|S38*F-YG7n=5=>Ue?EhS`ia|T9+Q6q$ate?D|wAlD6YFaswWgmto6$jUo17M`qu>F5}~ay3`1a>tB*Gxfhwj4($*-B zg$b9i38oxlM6Bn`fAKZQAf6e2a_R1k11<|Q`z(b5Hw=G& zrPLfHV7Zh|F=!;iU}99`EuZF}Sy&G>+~W8a`|g%Z;;HHEvCOy%?XIht1LfDEoF{cG z;dA4eqoC`8R4mD$&;J6xl-%yBVG1U9H->T0nfI_l2HiGO2)E@wIfmVl3B2aT%t}Xb<85!>$?RDB5kYM3s}39}X( z?t~D|MMtf+&=t$d?I!Ng+nD-qSqcMQzi?OCAq8{CLo7in_I;kNKPGo)g3JkDkb)`t z9gMT<&jf}JRv-}pdzWroCgR1-Zn-8;WdW98QuMU*V7b;lfs1`Fz@BBJFO&o1ukBiP zU9^9fKL>X#enjR`S?i&sNsm5^}`2 z!rPN3O+D#et`3YzJMM1sW!MK_s1IE}Hy&O3-jwnNv~u=$rzc?X^ytVmPYU2hIWG0& zCR{kqeH*RSQ`IQc(5rA-6iJ$-RT^`eRZ-ygX~EN(1Z#L!q=IcYV;%Q8TkxWo^>p@L zh)naHbly_#sS9_PZibJSso~fao-}JD;)|a1!%dM3uv`LxIq|GbRMWfpJw!~qD;B6O zCg3$Pu`-`61KX*d1O>YvGpDR3hwFb38L_Hjtf6t~0_VeBTu^1(uqOldB zxfm(@1%b%?N+64y3H75;lLw)BykO?VjR>VOzs2CW!tD=tEs^KMehC6mPvh_MBmu7k zGWrITJ->3ER`qQVVU%e^SC>GAhmZ2tq& z1JK8O=rPG-xv;Dl(!KZz{Vsn+9VV^&7P!!w)L~z0&u74C+-yCR8g}@%VALJlBmbs>kvUSVpEVIVp`s@U2@FRnmy{}7Bb}ih_yTx`?)8goLL0Igg zP=JT5AQKIeB|~UmEcGZ$P9$@&(oDlT1sygkPdm;~4sn*H@dgwTg}GfK({iD+;(ti? z)@$20rKsE<(SUxKYOsfH2}ou@B+=C1H6{Et3o0mq0hl&sf7C&0nd)^aopAkzzp~l< z)ma}mtlkGrXM1_Xnf>CZ2d$cd-oN0vuip**DOal9yyk#wb8uqTZ{VhL8~+ne+&LXv zwGZrCAkoQm;B!xtwQgno8op*W%X;kA>eEc@mOS+-wzNB%Zq3!Jt`n|{L)pfVfs~EM z)(FKHze;>-E3`wn$a@9R3jC||cYysXPYst3LjAaBo8&gwk%G^;j>T5!^imqV)3X_@ z(-=u+7rADT>YTtcn)KC2Til$NA?y^n^+62YExu8zMbxG7oG=ecP13`Qn_LU2lONvm zR-8D1ku5wu1530Bz@_|6GAgHrk*TM6Vu3EE9h=YI^~u+ENFKQGRjcZ7F~Muh*kAM0 zI(u0uz0C^j2^783JgWgdSKp_oP*(HuW&Cb* z0lS^~(pefQ^{;*%H+tvuQ-Q1SH6P>XmwMn-FsBV?7K!2{v=aEzgiTbi%SkDt_G8`U ze3{^@(z(oo%+un-^J-Xm%76)nN+6!H-DF3=0G}&Kn@`NOe~-67p@GNK@oPcj;?K0i z#EnWTKVgL`nNn+>1pYRkE*a#JV#NT=oq1F&v{Io&zukt>n0|Oj)XGxz;Ym3Ls9mCXQkX^0w5+_f)3}&)2OU>y8q<_BQ5QbHh%)#dZd_(OQbeURtPsJf}_gY@{vgi6$E zHEj|S{lonmJz&$+8lAt&@NlV$m{O<6Tx*2!$p1+={Ge$53b6`Vi9FLMd)5o-pk?#C zAC^QUIFxCE^wMK2z-Q5q6zOA<6_EQ=0*3+2~+gTyBf3Qg@ zhVj{4dzj8A4y8$Y0!MA#x*_Qk4~0Dm_!`7`GQ{KVm*}|^i}_1Rw_|1}&C7R-Uidl# z<|OkTo!;Rr3ygG0uLwpO1N;5cr}>I8{pUCM$||mh-NYco_d8~xKS9T6VJxA7C9B2K z1&Bl@mL{Jr64cjT-`8j7sn>Cxz(OJfX$L5mWy2gnSk2=>n$jtRl{kCO{gj<&YSjd8 z2wads*JiV;G-TYirb1HB_8}qX{)3L&H~^#dr+4m3&R801q*kp4L21o;z^o0ktc4uQ ze@RNd`Gba@&On<-iGiS=BY9ZeKM@V6)wcXyUtcs?@Q+rs_Y1{LjhLa}i? zyE4hvx%YXWGXwwq=Nraz0i$vvy;*&HM+BRLy`*?U9{9Wk+7P6vpO=6skIydD;!n?B zpWOL!bJ+E z>V4rkV3uKW_XP5aLW%5xZBT`wXzVd)ltoMGm zP5u72ASYQ9^KV5bYl?<1?zWcO5=spB1~4au6R!(j0iS(v@z)a!0)q;{)tWAHU%W0k z+x~*hs;UREPFmSG420ryG?S0&2+2J`x>vrA`;Z2?PDk9U|B8Dqn6g}-itTs7s8Ad; z#lJLhCjbQ^eJTf8Ect9hGx&;rJ7Czr{-4G$%hGeUA8HT`v%ap-e0AC>v6a(eANh>% zqetj`LcuP^p%_>O6PvbTy2 zT+}7sOm_MnXkpkQ3rZFreyz9zjY(Q86;FTp-K-9gJ6R2(i09t3XxlkynsC$IRk~dO z9&39z6Bo18@pUKltkRYjD`7A2^9`zd<(z^R_CI}%?W>;-F)#XHb2YDO$4rJ?-GSCx zJ8{Idps^qnU;+PbQT0rnAz@juAt>^q3Aeqw@M7)5K&)8gCmT!gwS9mHV7ht5AlzvF zmCpp^fS{!kx12Od531C-+?&r367e}iC@S*0hrvYBR1%(K^VN?dmn2&FwUH*sfuosC z?*ph8Fe+MrVcxD}g%M=BqMPb*2Z%j{K@aaup7K}~$MV6Az5MRPh#B>N{NiC?d`)in z`Ng*75QRq>G=28X44PWuJTF~pZzR7tISd0Y`7D_o%4hiloqzF}z<-oC02_btTIJ?% z3tb2Z|FE}RBl3$sE894+u>aBY6>@>Mt8V|+%HKb2BQc0B9<~ZzFXy2!)HXhPA@vFX zx4gNXiG@Jii*0(?k6P3{o!wna&n1^%je1R&V=W3ay|mx8_OhhTzT2I{Q45;3z>AwlOIXcEfd3GQ}%A_{p;s$Byzme4&~ ztG+ALxVi5#kbNmxw?z| zj-6CqZ4XVi=Pd3Q;tZO?wi{bFBGvH|A0gAfWwI@k8LUE9KD5j(?`MA58;}q9P5F%o z6gXE)&o+r(i|C1?H(v+OiQWos9p%0d>{z2BW=SLy!u5D0hEB?^!EGLZ9YQC(UM-rd zN0oFJ(SFI<#hKbXqva&2VF?(^2YCJhpE`|ZrDlj}r}YHRSY&)TZ6tGiAwQ`!pjG{W z8T|qlFWj9$_NtX~vx)XpdX^V4!+R-K4lmm*!!SLX{ubUT&Tkf>`|gtBGG1CyCwfw1 zdmUX>rx`wD%u;1>S>@U|6G4?SgXVT4L_u2aN+UhoZACC`$;9+sFAXDYu)`NlG%Yyu z1!ecbu3am~pniAp4>z9rSsZs0xtY5}!UH@!h~lQv#gfda8ntBk^dQp1b?mUdO>eD+ z&f6B$9fFpp=fo#y!{3wU0W9mfb{P_O?fXWeL?*CQZvp0kxtYv~dCpCdUYd zxE{2a8TzA@q)mSy$7l0#a3#Nnh$72L{FfxoVmoDJq zmJ1_CdtP)mDcj76y_B~JPL*-1#+i9p1=X|Rm~dzCbf%9_B_DM@IH>|muCY_f1vsqW zezp7VycLUOO;>5{$McAUIF9O4Yi_*iZTYxIpHILnZ~fV66P@*&HUDDRD=!pT2g$TH zuDgt+%)=>{J?Zb82fty-U$zD&Em&T^Jf@n4Rq+3!GrFsZ&8mki`kW8K^r#ZEHpm-A zze6&`LK@=V#)3{l6{xSqsbkp(OTmIXkh#$R5O8dM#Jy{G|C=q63=DPda?JK}0EgtQ zmUDm4h`0Bz78D$?_=VTZ#X@Ze}~9R%oi8^ODmGIMr6! z9~M*T0$wH3bxq_*i{;&N$r`rM&{a)4|Pt5erxub%iG_ za*RgAb;W_tf@KOGy@8Or=Tc)!QVqo$u#27da}d+H;TOLF#Km=DLW^# zaM(=MgP+ak48lrS1)wF5M;7GyZj`c0xNq=1lr|-n9dC!FSd+iS32JQhwtDLjzpk<^ z702t(GUaLF%udKH1~0DdI$?|vC9%VHmg(8oo4UUrS!5#f;j9c1+^T9L^sS!{{XOX% zOK*di_j=>motJJuges_Ji6g7@Jfz-+f;LkB<#@cPf#Se{ZTxC=|J;xk6>!xT+J zT6mu#YB%I?wZ*dmmRiQ36eV!pcvw76c6QNQG?ol?RYGg63MY@N>W z1*u{r3>z~s_vvZ+0?|L}H(i}q7A~acwviIz`yai+NTTj57_W_t+ zBRko94f`MVVqR>%M&y2dg&+bJNmFlbI)F@am)l=KO0keAJ8+l?Mme+HLbao>@TDS` zz@NO+*4?@J}pLEdQ%Z$gMgg8h)P29qZHVO6N%h1r5fM6jd3)CZ)eu^r) zK}`Pk&i__;ne#h84oSTF(D^A<%}OT;y3po}k27U?QoC21PisoKqpgx3(TP7a+3?p6 zhlKXK=w3-QY^gv92-RtqOWY~3#VjQ56r2qJ^dnDh*%Fw^GARz z0Mab?kw4@WkamRWu)kp+yf(PT{u}ec4#@#A4ZF$Zsp#8UHV{Fm%tGgR>n>aRa5I`~ zpLLkw@)UdVl(c$3{OfYZoR+gTj+q+E#8;KIi17?;jt-HHrE_g4Dm3;3kT9(h3(LeV z$9n6CO&eBLCqjc88UL;$5%&O)r*7JS)e7As$13f#NRvgQl7E8?I?V8gt}O#uEKIZ$_7`Q zEsaSu=Xs}^t23=ceH*Vvq5Y~6;W$r+Y7u{&yJz!0&|lrlXrSzDx~sJuS@YNtO|x?Q zK(snH)5s>oMpyW!5*K zv4FaLc_)k(Z^8T=hf%>WSnIfzQ`-#5OIYPh{E*hs5!MIxCBd>IjFZ^IrctxPuYku` zg(v!K9$S#;aXFCkh_8eM0wn=+gaVrV>Ub{g}a1p__cf(94OFD zRs0y93>bav&FHe`9_oC%32t#Vd4D(z%qL zrmiskc~Y7{n|0NAM6Mo3MCk!e7>O}9qRakwSr(D_MMLnhI2^o8*DBRfdyjdJ>MC9O ziVMIJUu)vQ3F^m07tOkFXzk1>&Yl%FU-H8vY$--IQVmaWC8@BYCu;b?&zt3ia#(nc zW{rB78-V_!qc#|ZSg8*ErGm$Nf<7N*ATH&l1g_ZTY?5*|nXT+QJ$6h3IV_;M*bg$!OsqHQbIVVZJcs@uzCFi$sef01!@P(XF3vilhBe?!_LP z-mK0H7J9<{w0H0=aJE0IHGr1e65<-1VTe&3Ru!yJbfMlnqIoRC9W6543f9?dX%(-M zs;$%ox-ugG6Y{RSFi(kP7kZbE+W+SOKR_p(S!&cH>-vH@l@HJy)|X4mNXk0G;vmZSv6;Mgv zj$!KS9@mHull%}hsFgI~`dBFc?_&GrT8jo_uliNH+W21Hr6cKausIYILj57hpEGap z2CB)dpH|Z>II~D6ybn%%{`oSgQw&aEVUePV9a((1SZ+y$9N_?z!hV<%3p$US1f5^V zz1bC`x4*OqCOw?0NO)A(B`sEx29Xo;Fl*FvrC`tX{JpF;ckc2&nBam{$H|A8uUjGckbxEO7 z{J1A*qLS6!TOox11cifEEzGafepHYd{}|!<3u*U*8eMHVogF3EaJOR}w~0o&^>1Pk zrUmV`2(sV6;i!2VClfHH)C^6FVWlFRT&wWgUD1x&1YU*)hKjjFF0uOok(gC$H~buj z*cu#fr#7I?dSnoppaIB}Z=lKD#oIZ^*h^HFd`W=Kq{L~`ZlV!mQ((7r4>gfCok%_~LAEk!R zD(59&uUG}E;f)2QhZFE{f5+^ootTKu(HJK3X(qlJw`Ete*u_;JR4|cIycQ>XLA8Dm%P2D-C#f=mQlg0Jd)D2|eEZPC{eNjsb+)y^l$M9I>s0~J8oc6H5%fYzl zi==;54%lf(S3jCA5)`tXJryKap&RBAj8gcw&o5_?zi=N$FF2B&!|GXZ3gxO^4_(G zV;EqBWr$lGUUm^eon-$Lw-_w0wBECmjPcM@9Fe^Tp9sjblYmZouJEiOk7?9s9LtjJ zSJA%~q$iuj<@ zJ6JSIEkI$#aVx6HOL>dM(W_4ZL?vI|$#xaPH(`NC>RZ$?Wut#%W?hwv1|ZIS2`c#+ zdH>~nd?2X!_yqn<@~C;)27yg-C;vJxW<5~5IGGt!!}do|^vdH9O1T<=FGut{8wNGk zM-Jg1MKy0;_*Wt}xXfd@rYFW}M|Hta_wh!erm#o@IT-C`4lN!l5r@cqz)?b^<5&DM z#6^W(JdDHAWFanFcbiVj^ppnR*0G2Jyt^*)?=|?j7CF-#xg(|Sk=?k8jkMBZWn65* zlVR}4O}T&wT%W%mN($9l;lnz=k{5_K@5}jG3wf;HDDRCX9!Bve0z#7Vw7r|MNO-Td zx_S=?AET7~drAlF$Yr#&=cNXBQ@ea#Deij99-uP`gP(Gt+N`2XZ(qz8=t+TFv z6Vt9i-xAj6I80|Fr&G2!V(wy~8oYb-s&;dX-tjp*Nq;cMnlip}u*4ItL7lN({)2Qio5_FF4)U2v*fUI=CacKKN4 zrr8k09SxeOQf_dM+EoL{;Qou_lrswoYL#17{u$DO4^Fj21Ex z6hQOpAxzCn2gml!*%8$sf-u*~@=JY;$@SQV!=03-w_lyx9) zldYOh4|8!l_W9?1{bprH0>Ul-u9e)ht_!uGUk_FE6?4CwK5cUKZ5a87)#7tGQgke* zPKmpbq4Q20{Qx+e3ICkOmnFlGlhoJs0Of<)R@u=2^Ls!Oy|^+H|6ev5&OE^B^yQ)P zQ0M({l!_NqYR72v7{~YqsCx-vjJEvmi=mOiqnNR>siH~5`bGs{nKoW~T2S#5G`dS3 z!=s>K4|Yq!Z~yYr$oXo@ske9KOy>?EGAF37`V%BIl;mpD@dDyTjEC(tsJ^5|@?Bn( za;jf4A6hx{q3kEiZN`_6Kef}VaY>oXrs)@gR9KmzM_2zzWEid#%Xn=9L-I0kP-o=I z;LbPbntkF4tJQs6HGY3*wS9CY4|PKg`{ha=^7F{?nlpeW(4P9$EC84E2D;+BdVsBg z5&iqWuX@xrAqk@2V`^j@+~$<`fD?}|T97v8{C*_%>x6ckMaMz(jea}0#kUJV{1if` z-Qg;S86)nOI+UUPHkQHnn1G6d061v>;s+3~W!1Ha1w%lPrvhM|X7Rhexn-5N%OC>yHb7DFbnmYd^|w{C*-BK*eMFj`+GU5g#OV{IbUT+3_4#f zhctmoKzdN_A9v;7jlHsiyJa~8s9+nVig*wo*YvG)J{%V_oc}NviHT9qMUO$!qXgGK z5TyCsU9s45`k5OA(;^8uTuN2tpYGL`N81Lmn;K;2%IL|Rmx>}J;gE#Kj%N$0f|9Xx z;s-vfJD1kJXwweoxc7;0qeFA678MueV;2vJA^%`3kv1;b?8X?Tvh4{-;h6@h~99m2R|ORHfKi=x%NwUDgmeV0qb-3UxnGQW`%maKR- z&RkrJ?Rv-0_mR!n$Cm{733cjjg+`#r%8zRCl6%&Z5)6Mg!V*bWiBIH^khKd?yrr-ReV~V`tI7_KP~FRbU;r`H`0YufHfSN=lmxq$)azL+;m1> zCme*wtg3VSh6qgzV>0r7If0C%1Maq6jr)wN5yzoYaP67rgQE>m6S7 zu()21UAR36BdQwahby7@V7m_h5;y_|z9o}QE`OE5j4NCI_IOhA2zA~Z+NwrUH)kiv z<6XmYHZ0jTgHQVn5Xlui9?ZO&1LRP6S~86PglI$s^zZvxuw#`;ZN!hcjI8G-&~OFZ zxrX?)S#XyTGPlu~tV9b{&vg2A2@{S{dT4zS0qFO+1%Z#jNz3nb`i3>*K7N1Gg|_N7 zR=5mPBD3q1PoP(P3%Js4?tgU$2V$6peU#Om7tX*(w|}cIxVru=X~P%lEQKvzSf*}a z!iH*O9W7QfQF~SdP3SKx@N;6K*7~%qf+4M-=9g{pTX7uQ=i*{kkBX{sE9gqT{281Z zVm!XzVDGF9mhe~lOF1O7^s2Ip#?`kid|8l@#5$!m-n7!tVwwR)%k$ecGST4&Bz#Ie z)6%B|cy`UCTtM4RT^_Vjzd*7fDDBc>k>(<-5a;?RcfTuIyr^1AYrP%U@aV+R8efCI zz7-YnDjrzR>W=@YRd60=RNR;+t;Cq4L8LFv{nvk1MwSHz9Ws+An6b)YxfwhWl*uW+ygX8G?#{*xYLQ+^bcfzi(^iLu3!() zF?028>rb1NI1JFUGUnMkHG1IH6PiGae zbjdr`q_mqkuXl?efPUlmq~DS!-L`+4l3VwKXq93L&e! z?@ShUbgc%S+w{v~!VkCQEt(}n{i{w2eD3=xlJ00c+KnC>F}6yIm&b)(%%s?+@96+# zM}-Am=*F_Yf|Mljp(B}aF=C_twPcVdt1)*xeZ+U|LI2Rjm{*5wzMI|_-7nZR{{3(K zE&F0m2XtuCI*u+5K?kJfBw@nne@wW<$}1l4RFUj8PMTQx*1nUEtJhcbyL zEhY#oJy_Ze!{{yUI%FzOxx>2Ise4Bh{{7V+P<6Ge`82tPn~B=7T2SM1Zgq<1tmRl> zQAht2G%vI!o-^Vm?w*9%8&>1GS5c2YEfr#wjbO9CX7n~>;Ky>A4>Ra71DX&f74j7(NL{(UhYwCFP1kWeG7N=*ve; zm1IA=uP9O6Z7iNnZwWHvtuAhtcCzY+LZ5cFjL{l5SZj6DlmYBQjV>SQ3Qguud{na7Zl`gG4$0JiOD>Q8&hQO% z{zkf)hI_OvUwYx>+d8!mD$IH(B~|LjIKXQ=#{0bQ`!Wa6!YQN#&cpx)pStd5TK`P0|Iw~t_&{#`x8Docq${4-n}R;L7oIV-7~K%jNM z)YCWjFLCbd19Lp-y7b=s{z+V|Gu@r7+h0&0D%DX;ac*mwWCn6!l62UQF^_- zYUbpUmibzHsLTY|HXEnkQ$i_FivNh%=KJ#e64+s>(0+YIO9Z@eBd_#PM7)Ji;VlyY z^E3V_zSNYZB;#eVa)%UI|8(V1fl5YgS4j%ArBr!d%nn2PN z49~)>q3dBScjxIld|B!Ze{|B)xNh}}H!3z#lW6`S-XPN@K};6;H2-;XE-H~X(~Zob zsHdt-X9{`(%owJ27Jh^oYoeL!rv^BPt4(`fy&hJQC~`G12l)GnSbGjH=n zJI*`Nl>H%ww2@gao-4~k?`T!0sl>Ux;$qyaviq36o7%gQT7?P_OvPbH-Ztcue88R> z{;pQIRMlkl4eG#~5ELTyj9?|;7HvZ}*?vJC@UwYX%L%%x*kz4ezn z(|HjsvU6xT&pI8_wdm+L+;^XFXo6*so$|<#PYG@N(+f{qbDf*0s%;3i<0+AC=zD`n zZ$R{vSJGTvv+7s(*#trO=}ttNzFOA0!u;IAd+uVFSX;=H%-p@vx<1+YqF6;)9w0qf z08BdZ=!G2V*wG4lZcYE_<;iMw^UU^>Y5nAEsph=SsX6SFy(Y)U2&41XlVE#R%t=Ux zZ9e(L&$>RwZS=ZV)#0$JF}hSsdJUOPyH}f>uvW3W>2*T(v!4>OLDBKkD|(sPO)Wc+ z>9<7Idi+T&uDl22-vmRgHxPWl=HESI7s066yXv3Xc4D6thwlEVXoYj*_c|B=X_wY1 zAJ*bjYkM#WqZ2dut>I_E+;b=}E}rUFv@n&m_p>>UEHgNu6{_R`a#P^Px@fp~fS$T8 z1Uz%OJ=>_HX+0BZ0wJj85kaB4Yq-^pJX6FW=nEOa9{uYxd|mFGO?NI&3mWT$)EWrNspdatBQt{J&lGsK-rc9ieaM1i$xod ztdoodd!9rAD3uNh4s>c4I2~Sk=T->x#!L)H?o&nf?A_YzY0~lFYBXHy#8Jo_1}k*W zNoM#DXK>gF_PO_y38V!H1(BCN49r~9H6rV`t*=R0YBV4maS)^n3Lj_G)`=PbA3a;( zl=Jc`VDU$spCXP(T>?1PW+~TDG z0~o=27oK&?8C)|BY+j+=xE*!K^bP%V7RE^M3#Ie+^t?C?*nTE0l>i@x6dn{u=B1KU zP|L=JN;g~ovM?=`{#h3m$^(iBc)BxP+|Inr|R%qbv{E*}N^6eM< zg!k^Nzhm|Zm#Vy7q7=QnUIqB-Gm)jkLQT4vK1 z{HLqdRiAx{3{~LPi?gZ?3n6`9t79+@UcA3bc+dD&=yZSY?ER@soQTsEzeop6^?~ly zHD7mue-5db{qHtv9kK^G$J~Rf8BW0_#=?>#ND?pHadtjM@u8v~6YJ4B30%hUMHBx0 zCf;{p`ICx?YOd$kEn0ULVmQ>xjGsH(Za}GHNOIZpA==iI2+hyD;%2nx+4tYK*glb? z^zGT=Cvl*1BFH~Ih{AlpLD79XdZn6p$S=dtFii`6riV+M3E9sPX~T{O7!y=F`xjDB zt^rmeMiuzV4GXwZI+ZC~RY}yoIjEYgv7Y^kiZP&?0-W!-mg7pTvOk;ty%xToisv4y ze~x5ad;!li&`IwP9NnG_pVc9hL>tp;Nu1Bm9q$BCY--3|`Mb+@$xF z=XCQfmn>2OVq(xK<{#Q$pkB)Zh2=gSRLfR1dFG-VKxf;vJX~D`A^-~`K@;KTOY?l* znvrvBwOnk#aGh8h$ft+0_-M<^cMac#WS^q?vTY3A9Hh@rTOHy7;(=g$<3$aQ_JBcI ztK#$~^{NBD7^5Md)BU;{(~vrybBTI~Mel71%e=Jzdrne%yd#MHN;sfN>JH&-Ui}bF z=9WuWKF`pNzViwKD9~m<&H2p3yN)Ox*|oKfoM*%Br>^IIJR*ILTqZM&PCOp}TVBg$ zcUb7g&q036Ae8ruh2Onn4=z+ceLLYPz!(vIH_-Cqu#r?+SWl=5{!RAHkU&?r75i_y z`!fT9YVGDJ^wY%@ZE&LL-evC#UM?~^^M9AJkgM*_O1Dg$Os@hjBYIpC2IB4%dXR144!ZK6dAV4QkGBY z9(E5E&xQAwHK+~`;J*%OoXf`bMbXI$*p0Kg%(i00FW#j14Cd)jV?6!!R)zuNM=mTu zJRC#Au~!9X{dp;%V}bSqD&}jveJ|Pw18*<1$~fkMC#ls`R@r3J8s@15h5YrvCqJmk ztlq{pBUy7ReSX_@%}eKsuIwG$v~#-%UjMyGwq+1&qxw!qM;{5+3d~2^&?iGqQ9HL~L|g^y2rY#o=oP*2YDPvN)JPC~v+@5eDu6 zbwtUenlii27DEdCmJX}rg*p<77OJ3w!rQ?M_wh$emuBD?u)l`ZD)8vK4NGbLV}Jc? z4UBEL-NYM+;D>hc`!Zkq#_Xa~)IQQbEyVSgoa35PEccIm?vZ*odhInV_!Bg0?)8@B z$#cb(qtd37?*aGHK?iEp8Es$W&WP{`{HQ1$KBFq zrEy+@27t{$M+wD!{b}Ct29nB+NYKRU|P}?l~K>P16Sn!l}TwX~Bb= zC8Ga*=dv*u&B|6aeE}B@$JYvPv8@`UQ^()#O0-rk?H+>}`1m-K_CP{kw#Toly3z+{ zWH2Rv^jdDeZMbleII$5k>->QoD`OQx{curXjyOOU4$_~Pq^Y3d6spRPr@w7mdk3|9 zOla_aVbCWZUf$-pB2rOSS?|-*s50$j2{YMixL)eze8Wojr6&ub+e4~T*ZI$cD`WK( zI8m!&0YpAT%&@ybQR+C$B|8A#mV}K@)HbU`$q&0yE0+iE0j_;oi&gV|LXV*Z`~Q8vVvzX>o%W4f*ne!H<*z0 zuaI)8SC%;xPAq%Oj(Szzt*D08cRq+Qf)vcZ{(Mxa`@Md_jBCq}w&7}2njq|Gz6-fM zu~}p>Bv5%+t08)%8kgspVwSn`tI;P8J4f1q*10gJ!USQ>$lSirpk!wkfb}CLc05Zs zEG@(ptAgu@$FTbwn`T~|0Lq7m-Y=%Jh&IPWf|6R_hwMy${$ozJbGQEyOyJHI z;TeUEULp(2#nRtPm`Zb6;_IIYpES6S+Dy$>lB87PPk-_Ac^&!4@GU*8&UYO`+kD+G zp82+)=3s-s6^@1W^)D(`eKfX9F^BlnI!+WqK$NN=Xj>#NFP!H-Xx zUrv2!-pu^#o&K7>6l--5b20aAW9k2qb>`nt|9{wTQIR4;D*G}s82gy)$}*VEHpWiE zkhPE{TPizQX2V#+3`S987s{4VDr3oBL?O#3SweKr_x|ZV=l%=Kao*?odOfe#bv>@x zJRAx0Wq_vjnmV`$vn1~vv#VEPmXz>EK8SdWzaqNm-}?-GaAWa?Na(ZS9TA!4T!)+w zU()1T>RE;t@TCD0I7Mv(sWuC4P%eJ`ZzzUUNM+qdzd`z$1^+Efsn4Q)C0u3kKmt~4 z;`@DhgWOZNlxA2v3Q4C?)o3Df+EWflU7qJ`+C_z&KTjeGQrP+vvIhMUQc}6qqUDR; z4A*1;vsfNO@Wk>mLCh*@U-dlU-0_j(KjElSAO9;O-P?O7{p++VuX4!LwcUABc0TWd z*4gV(zuOTI8(e9hQ>Mv*W()7+l>aX1oxfeFwb13dYN;$mbE>bxxe3)oS+ZimJa1Wm zE=(2X!_KNQ!`INLmy5z*P(X);F|r}+0wYkNdU%u-SDpxB#W_Y4EHrydiT!Qw7;0T; z509SUGzfs#m_%*FEJh`Pu!c~i?sk+jVv^zSS{nF3nymZg*UhN}=7|3y~>gnBs`R_vnv~+k#-h^e4JZUWmA+)*SnCw{bxum!NP3hl&P0O zonvMJ?0c#)vk3x+NFq7XTT@$WCv?VOw3n9zpQQWn24yj?%E@XOgPg(JN7#SoJm2&zwBlTD%C#j= zeWl$S_uCjBsTpY?DrH`n&7`ho|f zzhDAY>i7Ok{0qJNb$QW4h_@QO{Pg;4NZ>)4w;^z-W8{~aa$2SdYu?)lVy(dH6(Ic% z)qE&TT~Jj@D1~m}8dnm0(!&bKCib|lF!Wi|HN>4|!Qy4E{Vj+mWGW~5u<~X8E}9PY z%bi=Q8!4^VMPYqRM^nsnx0CCItiD`LF+X0xK9>Rj>DjY&xPq^6mS4eq{}~Accv<%x zNw-VyPqnyM=$*Yf+zQFUG0n?$5?%Rw_oZ_6(VZ+jN*bjWE(8tzvgSV=Zc*AIUwvGn zFcHY#k_Iq2PyH^_5;LWv!1g_NAr+`?$`>!;Au{)4w3&)oww>T5!b!!SH(SQE+>AdfM!~Uqr!a2*{{xy5MLtpgw3BvNER~8pP3=8NI+Ys3rKIS}IlWrDbU(#ne`bC2V3r?& z6#HeBPpq-2Hl=~H?gj!_`aQi5`)0q9U9xmEmt90_pjb%_oWerpMRtj9|_u@YxN(~D! z^$TReB`tpuz+|m~jVw!tAM15pY*S}SQSnYv4N^9@5!rj$@C9{xdyVF6t3Q5;ZdM$@ zPri-6;95ObV7ssq{XqT_YST2zqfA~)ASDEpDzqu3zLrncoxFrjnlQ8qtq&iOw1zGB z{rek-+mG{*e9ZdzN&a!qAGh1ottmYglkP&iMwiN5TAtOa+%; zpY9!i4J`uX;%EYg@_pCr8}UTC_4j@Pha7 z>(WROCzUYh8MqKsuA|uYZjR=c8P?t)P7+#quNH)0-zK>W9c_6)d=SJs{L(Twb zm?w*KD2`|j;c5u1QYNsi@z>vO=QRmFes;R-2lT2KzU!0N_nZ95rK*i;z2L%+yb^L} zzVP3B-AMb&+UyPdF1_~TLUjx?fYJQ-XjqLh@Gqm`@|;)VTj}#d?pS!0GufUZg|j@1 z$X1(u&$hj4A?W=yPEJt1V@~icz2(oWnh2Y~&+245E>w$aL;NJIB`9B0Q0~jNV)PW- zazhD8q(Gj)P(o8MkE!Y1{k9ztT9LBerj`Kon`avJ_w;d;NU*GxbBgq$clN9S&`>%) z!#mZ9U|iW(Fn&*vgSd@+&^Gbiww30hKLwF=SpfqD zr%NVt0_!ciN&#kI%8G`xq1q0oU7;OFUZNJLr9ghM16neABXd`y{2m82%+0;W5+~(B z?2yvz(3-Y*vpiQ8d+!gYgr|+=Bg8Y5B{I(VOxB1Rxc{z)ZPASEomUAX;t%;g&)grN z`7gh)q-o{Zwj66cP5b>SVoW2V#lnCw_NjL5GMt|pS_}8qop}ECzsfg9>K9Ugh0o}s z7G^&$e16aaNTIfg?g@|_N&nd|6i5wC3ja3quFJh-jQ2WM0OzNR1f=JjX|6f|mef~h z{>^>SFF?eUfs^+wp{guI9;?T)MaVD#XdJ>_^Dm`%QB1-0viIFH=3=gE9X+N?^HB~B zQ$(NQ;e4FbXYBXZkq#i$*Aq=j7=ZUxc=$kDw?8Bhnr7*#C`bRZW>So5ISB?o$&tJ| zpl~}0(*`{hdQ7+CZZ-8JIhn1#&E{eSaNfl*_(ET2(TtOS8Wg}T_1cgdfPh7&Mt`7A7h&UN|t6E-A?2Y6iOwBNUbFaM6t z=x=@aH9EBL$$)m;8a+J6G-H1*Pb-1h$B0fO-gh}iMM^_5IHLn1>7Q3Zrcy_^t5hP= z?w{&_TZ6U^9|MKUcJt1K`zoUCyVub*$jif@82lpqCJCUr&R{7jIL93S2AFN~U|BE? zv%og*=i<(=+Yu1%_OgqeT{M6$wC(2PU6BOcSBEG82FoR-weu{7mrguI!lZgKqf_`NJ zO%jeeKy}Oo7})j3TDuf~h6*MO>L6sFvniA}8Ugh>Y4zk9IjW*g-o}9`){0 zv|nRc%$NKi&c-hXZ=O^>``Dn-uI}#aql9XM_^>w)KkNgdDc;hM1N;P9GExJ~$MI2; zXL0~sSv!jZb?7@xIAJUO1x$yeFBR^}q7%(^&RiatCaBogTdr_65zQ{!7=i#$>XO?O z;HWnS7Cvi$5^giocNd-2;ID!MzHee%^=)Sq>9BWPH|q1Ri1 zLX23Ot*k9!Rcxfz*NQVGT)0g`@2UgEYgpc&f#h9@M}JP_m_{Dk6oyjX4h=G?LlK#` z?|2Xz-mzNEcpUPV()IT<0+0}g7T#8Be|;KO1Ffl56;LEtzHphc!}<1`*o1nA@{rCG zfg%ZOCqTeR72XL--vKk=g1=-{yXb!a-Z#x_?`d~-E)0aQClY`f=I`KmfuM-el8Ym& zpM~ov79?U+lRKmy5|jx0m)gLi&x76pm2(447#s=rP32x@A&ux|mzlPp6FKl|)LR5) zsNcjJS9?bDJeRZ!KZ3y6BM>q64r^D|KN+3M@32?QEt<6~m@m@R+M&sezZBl$fTmRB zv+oh$C#%@X03?-_Dsox0#upDT+XfBoj6U-59P3LC9UPBZ2h5qv|Hg?wZgLE%LL`k4 z$y1^*RJb0|@NTae_7_6SLhbM0mDc)wb2S52{r#k$z@|rr`ODX1Gt|0SvtgMiEqvJE zOgTq##`pNZqKuULhQqvfQ@N1?AL9XzDi4dM-NHeB&Qs`(h;AYwhE3?qE9IH7*ws6( zjoB1jAr0^D@B|4B97XAgQ7cn|jSaQSeX-ulIPhENm-t}?vxu?>*t-Q&_Ua7~pHd%J zfl7ToJq5zGNMe2{7lDjf0VcJ{JM8;oF5y@^T{>^T{0ZeV> zBNf@0<0OC+u{_tAlzeL)751$>K@R+|q*WvpCHC!w`)ANxeYZZ>+AQ3?p;Zg=+1vr< zoGC~*CKbIGt$O;)y#yHi_lZ~rD#Wy}v?pFPVdp|qIC|h=@Z@&C1)F-7Fwi?}RbELz zCX0wNU%(wDKu~GFd+<6=|3+GWPcX39yG?m7(2J#$MXQs<-mz!BAaxB#xUEFWQRe$^ z9~`KITX0+5&erksJ{vhAxCWK!S8#jL+@d_mAE_pwT6Vs|E9T1QsW?+=q@KWm0OgA(ps1 z#!%6lEU~#`!)%u+6P!$LP@K8ZJb7lme{jTL#D#jq~ zj7{j%r%3h_S04RZe0iG>4y99&y!C^3TB+S;$}hlFYjAbQ{6GI!VIzzl>q-BBx;yNw zkvS65u7%O$0=?zW8-U1$erx}s6-;YSK^g(yx&gphxt4yU@6Jj@%(p0eJR#A3zvI%W zR`1q2ReB@+j85?mz4O+ewK$2zji6tPBKN;nv?*`jEePAcamkbpd4o+wE_S?Lh_Be% z{#-6gwD57gv}Ak-(EX6$>8@m|clmWc_eQU^Bqc-V4#uotqdfqNRB+g<#!ZIG8H2bt z1Wd&SKH&0Z8|!n>r(gqoBEc@DkFb)I_sXAQRwr9`?pH@3XdVNfgLiui0!sYO6A&hZ$d6+a{(74Fzu z?vU**TUPCyrp=tQzl>TliCEL74rmn46-?!9Igo>chw3xekn_nhKaBI%6`sM4 zEe5inDVA_1HuqCVpzzDNawq4Tg8@WP=qGxYZbT4{6BPXhzwk!ZD6iU$fKM*7f(?`b5^l0A{E5s^IjCf2;8=P-(T^xkOw!sW zZ~8LRm-mK$SaNxUM&5ste66#8!u8rE^UCIj*K&qj|0SUWGsm}$5iSw1mGks%H!-T2 zb?mGS*I8qbY4m&8QLvPCXp3xbNuD_-4Jqsrve6gvh`4r=kL(VJG#jj;Ia1&NGhS06 z>RRJS2$I1hm#eMiT zrpAc50{ z;(cwe_e}6>HyE&%RC0UbwYZ*qikA)p`sRQNZQXirD9hE^tFQT;!0)1=a)q-lRfwCk zL*eHtYmzn77tAW+ru$qkp?sfdD`FmU0UUmCqV+k&4mrf+K7&$Vj=-6$`F;x5Z+E#I z^cwo(og3~F2onEh&AVZ5E_C@kl3$~FKf~ETBn|&0g`NPg6(TU-KwfT6854_~ zN!qOh0dqz!E~>$gNJl(xy;z3dzoF71I?79l2B+E5BuP9}Zh9D4_y8NdJUJy8EmZK0 zRS}cClz!@NK8yLxA;%Wrqul1_DQ~ThdTfXkZ%~;#LxSPGjDIwzg)+h+iXy_`IYqR5 zEllbmKz~yuoNaN49L~=&p$Zdij<(@+EM+Y5DHc8K{VSvs55O>&O@9FmfUGQJUO1Y4 zPOBZ0Ug%gT;wW;=RUw3osJWOFT84meFkjO=_PvAhMn*=+j$dcJEVK~S@Too@;AKMF z0m<|}(NJ%eV;ig{BJ2rX^48L|!)eux()qzrj)eFdUOz&SK-KLRPgzCt(1$oAeJ1-E z^xQV`9O{SFS>y7M$YLyzDw~P?eVabq);aO`hC>&nMW)5hBP!#it8{lGf ztv1dy%kuFOcH-kviAO3bEilOwe%6t`5IY&u!1_q@h&K34^ZCQr2pmc}zeA?k%=b_r z#w+H175VdMVP-CFvW*TG`gtjQwl<|p7G4C$=lDaUtgIO;Cuu)_iAq!%gFgoOhS4`@ z1fuz!_clw+ch!wRqtAkvS%s22-2lew_v6yhz%=ht&Ip)}DDmy#lpe-8pzEcB}sQA+1seHAf+EuC*`*_;{ggP7ueDeSwK4_PV5@fxHes&LMb z;GK%0*`(6S9M({yV&4Oq0wmiUf2^d>4R)!>bM))wv9PwJ=1ScAMj!=6XO;m@ViuIp zcHwk?CizaZTUZO+*PZLGozz7+!gQ`PvEK;(oGV@mTmsAoj$l(jTtK~QBxq>(l`4*< z*G6}gw;o~sY-#yrpqU^(XzOdh{85SjeR6aFX4}nsj&AmI&9y%aT=_E8khF$Uc$}Ar zsCvf#uLH-TWq?aMe!iJOvVS4~?NL_UyX&>oS-?uI}^9O_>>c5sMXlH5OvYFTgR#h;?T+qh0KNQkir z%7t7qvzF)a>tZ551_p#?ElUV+rS2F%O#k^AU59W=q210gzZ32Bj>Z#gI&)U0ZNMB+ zhq*{X1;M{&`QVGBqYsqWogp5f zpaf2gVxE7+1>-NKz$yb~*+dQkWBRWA%!kI~tg+Yqwlbr|>_z*u<=ZpePv!t0^>X`M8IsLb(>~EtpBGW_g ztyVKUsV;%a%_rM&rq{bo{-w~ndKs*j|?!5XxW zMafb~AO&{IEglX0EUln4lK|Yz7oO`r^Bv2;)R@&KPTXD;k8Nrf5mNn*YK zM+ci)?=;2U7k*5`+M$zvEzH9k4KHq^wNI5zA8ptJP;FA46{n*HG{(i|oU>H6On8xe zT!lmn3xVJw{(L&`!+Tk#VI!G$+>j7A(WxaEevET!|4Wz!YNKAStAy0v#j8o}mQnMb z5YHkoNX~Bmx{F_27ww4V(_V)ku6{?2ygFbR)L1BY?jF+J!$Bxb5PS8=Mu~oPB&moY zA4Ao2Q-BvK(b~^Zc%y+-_YZ;1X0lhf%kQVZynUs8^SgP<89VwXGT;6t;@?k2gpfJ~ z%0O>C89A;5Ev&4!Zw+g}(~GeI=&Sd(E~pF{4X2o?EWfO1b`J=?1u#XagBW;&l8R7J zMTgdFU>V!72Q#h+xG{S(_AiJSfvgC4+7^dl`}Oi_j);nRM}Nmufs&$sMP%!Mq`8xI z%Ej3z_TT)M@iYun6-3x7tTQglxC88qXJb*Gu2(K-D57b{uwi~pWkm(yuD(RnHG-pp z5Oi=vyj-_a~1N4wyO49;C5dyI(4%ojNo_ zvURk@*E>dDj%&v%*Wj&!p=lq2ysC?5w)#$Mjdajf^$31e%#+g!n8aaFA?`5PVRE%^ z3Y>1+2IVSSr_6HGT7LKCAce8Z^~x0el$&-?c8QPbrw|Itcd|!WOmCmz4IRz>h2H^f z{;=p*zEc#vQ!G4u>%&K%k-O)>s(Od33=d3Xgmp*AtWm+<;O{%P*F{_?1MYU9c_LCR z=6#*O%o`a*Z>;s0Cf`;k+jS7B{h<-yD29O56QIJ zdcXH!ViQxrOGy@AjiSYwRq8I)SG05maQ$L#dVZU&kGejab1le*{cO5BD@^cFFLTL; zJi{oU1CY3HwK|~gv5i0_%$DL^X~B!feAt(nYR+$4XNRF&*LOg#frT{IK^$sKZjv0r z?*t`mdaHvn0x>EnzcA&or983l!(r)RB5G8M*~ebCNv;pdlCHm{v8=L|-{o?UZ?8VX zSR#dD`Z`9|SoQfjh!7c~`!FHpPU(-`(k~agN=r!-zp_86l0n18TdVJyt&OM-K>%a5vVjp&(8Z zdOXfG#UZeuTi zZ_Zdpkw%^=5)_t=e69_M-qJSd78My)LZ%0xlV2P!Rq7PYL1E4jnKHr|oH0{%oSP~{ z$IQEfgA&vptCZxHn*ghKz$g+h(v+YGpOno%S#Z>@E|(j)&uh8-l~21;fPDWRJw-b0 zF_P%*wF4TjkLJ?Y-MI*s?SaL9aoQW~-IYCSred)srzGZPtMmY|kc}UF9_UTQe^C>W z8eDrv6KXv{pM1n0=l=|Ht)&;-;J|2>#qR=5kCG;uY{jn_{X)@*`r2C8xAEv%Rs%szDFN(b|`8dv7f@P7&2l@|T>d7>}2*K7XtJA{sR4Ri6HU z1`1%nDPjw=|Gw*WM`?g-w}kzlvr{|3G=T8{5E)-6SiYY9fbVpv236l6{)UP_C*nPHa+<`AW!& z?Nj4#Qx1LP1hHAt(_A4g@5si+MP=5?NIK!AQbEJ2b0Z4q*zMM~1um6AHh3!7f{1{q zbAfP=q_Gi;)o75jcEke@Pa+0!0F7bi1lema2ce4?>>2E~a?DOZf9W(}2t@QpWy$7X z06rLSFPM~BbJzRKVwQui|5ZP1d4W3oQ{QXkQL-dsB>BKwE6+h>CA`^_G+3k4sK^9H zf-(>zKr;CN>yLE_n;IgVq))%e=mE4R$jL_dcJKC^+`uw8^_vmyFF^IA?N6-N4S?Jk zqis5gdfQIH`~XJ*Xrck!8SmK+8nf>#Osg5ek~JyLrQQYha_*s z`2$S)p1zMaw&F^W9mZ<|N4u9Y86LYf2rpn8=jjjtL0;r9>wD<2g-)1 zi0z-XccOE8Sw1!#^!IG6IOC;Abl2@Os7OJQmz^VFNLG~XXzA<;D&WS5&SjNr_d3`! zkl@XVPR(4JTn=cF?}JT>zfI&LjhOOSFtz?iHRi?A_ujixclQTH@sY=qbh{pcgu&Dc zYJ%xxMd+#0jKJ$)5>)Wo@D4n?x^dzbP{@zxv!QHC`3~J77f75GO&NPk(#PB zPWW?`>o0o65%uWd*iT1ZRU6DWvyG!ZxAY|GMEDwFHbDbQy3ES7eKo0+dHJQzn|60DV$f||-q?J#QSFMnDExJ_cYjsdPPNTd3j4yM0X<_G`6n>(NZIb|vh1{(3y%6eXU(@7e?OiVAk>GPKgH z^H1=QaFq3-Q0YE8ADl1hG^se~^n>4(r-20$yR0`L%aYmuUl(GIUXMj5@OY8MrjbGTBZbHbzbB0Jw$?PAqnN1 zxnGuNANy*%D3ASRbN+A#DRkp2%>f6{nP&-XS=tL)OK>__&!1NKgvFzJ=+tK{X3gy?s z+)cpDpg0-J(9e?QKg>XHdXlB{T%2G8>EVnsg`f)^lWtI|!y2aiCtu2Uf$+~Kn~=zJ zgO))IlPdO zYVsL0v2}B=OTGRnf5bj}jz>Pj{4d^cOgjM0&Nsaegf*c(W52?iioZBjnRwZDqRJD9 z4MDZaqm$Y1`*w}!H~2o44Bg>iEo|v^4JI^MgYvhA4Kjq*B$c>LD*G&gq=U8!hg7oirTA`P5D;w!1pzji{Cb|eFln>X@CfK>fwN`w)Q3xo~Ut4YBPh4^6qGVD`Vv-FajPyml@~ZM9YnIZJiKk0WVK0itZKs;t{nB z_5hfYMUh}N80B3Ve1NUHdMwy0juLC1K>b61cS}aWLht)0qt2&CwblFA)$=J-DW`2Z zWR-IRD{wWXL{Tal{I;fTdE%$#$V*}3DDs2Xcn<0+Zv8mVAK18u)#>=18exlaU~nll zx4MmvJ5kcv0#1+?HW{~~0ZiAC_IDzO`*?M?Pw;CcHAfTb=d{)z#(s&~GyLk6X}pV$ zW^IJ!d~tmx^8!CP9R>18-1}z{(iV_I&!t((8~uB2@F81C3UZ3>UzUzk;F8rLS~zR8 z$66!;ZCtN$l?fsLO5fBL1plIaXv5mg$|Hc3)l}RGq%_aLBlz{E7L~y&U>;dA@73=P zNjmG6>4-B0v47X(gyGB^Fb2{9ZBZ+EEF^L9i;DI6KM2TBNYWy~%k_$m*HW1}ZS7%& z80Ei^8@cN1U95pqOb!E>=S$l**`Vk3I23KaCY@QXOkF8WD(AP)LHgwTj0-*Y$L!aj z1_Z1UV!m+8J|fzdVeRMVh4bU4zVu5DAD5VMhE1F=p@lB9lLo(TCeXyENwPh40tM4~ zN~NyzunlT%w(^CfR9!)fzFFm%E(4ynzhX+K%G|~0t#9139Hz8e2@GwG_gv0I>ErhQ z`)5J(`_Vi`5Ak%`KYzasZfM0NJ*vNa=z5%$I+Bf%18-jg5ly|TLy=O99s0-txoEN3 zK?oZ2(CQh+MInHb?vkTVO478JkhBGvhzM~36Mv-2@B{~7l-XSjZO-Vs-LN5Iy<)FW zJwHp`F9xwR@fON><7?}Qs2kAhF4O>7r(wKK1|Z|Z6m$j(VN+JRbtYB}Qof78M8p$; z-&JGwf3K&1@q)?ddCvFO$?kxsQB-TfCfvcVY$~so&6QcZH}!aOrW@KZ;K2Pw5gS1AbS~3U|3H> zxip+|F!Ba@|B%k565sG%&vDi8d2b&_~XwspT>@Q0MwIO%!5QnFHaH` zs;~F}e4ev!Z=AnnTHg!P;tl(9XL@HNgHD{;;sva8tq zvwt}+)g}qu+N`_yYY&xA@-A{KpJ>m%VXDF1@ql9{`S^xOn~Jx-1IJ`NAtU>^nym@# zt$s3LY@&a9AM_of(W7@=53VeKR7+ZC4RG(#R6FCIAQaq0XfDe6U zzUI1WO;rK1L8+NQ)?4vd;=`3v*mLxP%$~e+BR%mWnqq-|DHkIoeai#2vvwfA z67K35;(!W1n+QGpb=w1#3KWKVTD4h;P;+&=nmYej$UoM8FLVD-k>>tg=*sB%&zSR| zgC}q=@4yugV&N;W0iV|y6vU`1;`O|#9|AT7SnL`xkR9ymX+GL>GC3<4AT`x+>28om z#+{p~^+zFcO#j>XJR2Vdj5S%9i19}%nxFq*KT*FhOq9l)FgtHQLg(6Bh*96H>Zu#~ z!gbCSO4~lq2L8NMUM%xI5VI|G%C0}EF!S;QAg^$j;R+;6LS0*Lxdm%lfYxvc#G_z> z96|^(arsq`)@ftaFc9=tG2=Fd8`V0Ng%N*VdjLQMMh#zEK5xGJ_PAB;LdQt>hVvI3 z^mx{blnAG@R3$-j_9Yab{O~3XK7S%Snj;tRqMvNu{w^k=ftbJwiNLAdjYA*wE>`Z$ z{`wIhq?|{zx|SEg#zaD#AQ z!y|T_-9tNv4wMf68y{@%e8TDP|AqZDeTmA!q;Dpts(>=xrBK3|Sd_g9rtmhJZD*qc=!ZcV((d_JKpgz0(0yz$(df7ly zVT=1C-RCTq@~<8*^S0b_w;xeNUimHj@FMk=^$L)B8AbPGB!EmAK;pB$&)uc@*5C=^ zW5`3T_q@5#5LXl=uER=hv5Nfu-_!EHdbj_SHnoawZv<)A3LWnj^gfc+9qi zGI8q2GK_7FZ>GCbvUJqHwtqoDYX7;YSN|Guf?|1?eHJg@?zQMB#tB>{_y z&i`BZR2<_|!HS1L$1{l+)sU;+!O}uA-0ZmYR`A#O!_WBDt)OLPPa@A_S*Rcq%zzyb zA!MNhtS;hg>i(u;x~-zbUOCN~np!@bFCyiJExUP^dd&r2CBgpy<$Tl4`iL|9%1Mmt zDWt5fy9FxE^D*CB1+xos_>~TLtE|?K<$H!a1SO=13LE5ijJ4B!V1Uf@4ew>xOU>j} z0?!;)weT}r8;A2)$o~+PCzx)XohcP3Ac|S;I;liIH>u|VLUK`@({WyJ%D$&*_D;f? zGS#y`Zev1qHs!m&btrF-POZ!+%Gl9}a^heYioc2W#>}mGlZ`dAGQ_dbr7z#e?97H{ zC)A4fr7}gi)W=F@#)7(tjm+(lA31Zd`=ezfX`QDQGM6>}74NUnY{-B-5($H(2jHL{ zk^nZzV;w!!%0WTV1oT(BiTNZoIr8IUa;GWtZ>*Jrx@DdR`FgNSY22hi5!s9A;zE6< z4bs!8i~ku$?oRO12?*o))+w;Ub!SwZrRm(l#wkRyfJ>nRy5F#vVPD$FnD5G+iZQkj z>MFv(8dLp(o4yLKtw$ds-T>jLG`7N#@ZJ&cTs^00>4+WX=zc|hBk0E)c54k!QKGq&TpdzsPymV2m9tu)eoWx|od~=hnA@ZMYW(Q*CG;7a6BQ`_YqT}<%L8yKiqV#7-l@=~|X$~Hcc&JOcoMi<|fWO0* z<5mt>a@0ziMhjL>7weCrAtuM`tI`g|c zmT$k>@=*uR=8os^w7d#pq*Y{OVz<~(&Ij%uD7vuS{S(x{tCr9j3G3lRO!eM11#Qtp zL@$4lLh|>^7v}muK7S?;NxX#8J0`xE`%LuLx2%-<5b6l{G2&6E&%mO0!`1aP;%rZ@ z$-1dMKcw2vd71pa`5%}0b@6AWK3@il=li24ZBo`VTWyNl4iku(C~_QU-euiAv+w!$ zBIn?aIusbMELY-E?P=WRV^3G@xwPob>-;h?110Nd-uL6o-O2VT>~J}Y8x)YXjub4P zoc#FqU1`c=tJ(PwECofByCKVnA4@=1z^(Jz!uDnBmDuZ!k0F1Hh zv{T>-RPs3@meBVTKzV!<3w^Muk)6}YZ(({ncto|0q>LFadunROZNy9+0S?=cS3iU# zFev}lWxccuT?v@#;8&@HH|8dotEw`4Mmmeb1D+MgPwdJ~;6O~5>-K0=812Jz^OO-Au5%2b62Due z!q!~d?Qiv>J^t6=@xG3u?7xw}dgcOq^&$H)^X-kG>vEKSM~^SLB15MuTr+ZvNhog> zwgt}DlgUBJepl9^nzw5wr+}8 zLtIDq*j>uGqI|vc@62S*C&K)Q9UYSrcxyYlxsmQc8x^)Y3F=#dEY{k!>_)@uwnE24 zSp{R+3!l)!rawYi{(|N%yreCc^S3HtR#1v*#`j~X7||DZRdG;1!pj5V&UvxHk23FQ zEq(3wM$0`uao8bzwrR|tFc%`q>*6(vSs((iO&V{MZ;@g@0O;D(Rd%;alJv1Cbw=!A zma)$x>%F?Sx_91zZnPg*d~0Oa;{Emq7&jjB22Iwd)KvyLX1re#gIGcIt6ue2PxlLm zEWc(vM;~-?WMfB*y(Y)#1b^-G5i|<2wbqDvHmxdioFc)G+kf_1v+O5erDN;j^(&gr zb*iT@Omr>T#mfW?(N z-K-Snlrkd>yBbNp5rAn;OeUG6P8$IlCUSUQO2{SsN=KLz7&pdSFQssj>+ghhhJ`NYjbjBY2 zcd#LzTFy&)LyG(}XS7S-T#UO0qw8oYE9u#br@mM_c^Nue~XCR_5&U8TOd@ zL{638?|I^tf$+;5elalpp<)AFW5%W&X5R}4jv*nr$|DwUH)?1X-x`+mG#Ttd$~0cu z@aZM^JMMMG>o>pSQ~!x=lG&0n&D%~7O~m}ZrTGx2LiG*xw_+Y|5z(sm{+EcP=igYk zX_fj=myj|8$H4djSIg>u{95S7zh(n^y{)AEg*xi@xM-{&yR#y-hX=vS(eFFQ3IkFK z<~q)ly8()#f4lZ4{xSlPFjiQpQy6w&fngJr5Qk8nA>jhIa&DvSb3pD%EH+5Oq^fOI zv4&k?9ZdA$CeUsYHH8jOrnJhMk1j|e*H-7V@nS(GWr|`gGFA>$ zRvIW&M9i%QC542#49&|66Me>wMhFf(W_IUjV-aajcakxTQD<_$NX^~k8q(w|6|R!+ zdOxwygeB2i=(^9bzup}5R+aFd*E;|kN%aj)73iYgJ=vT<7B9^?@k^-U%$VejKUtn~ zj8L0Yn*x=0fz1Sr2@~(ew^b{Z7FsO2Mlr%uXO9x+K)CuK!3+ z=^gohg;2Xe421TTG?^qd%dS}kA-Yy2hsmqjRAAgu@QvKdKLAP7WEj7oBE;cO2jo0y zQh@sDzejT=P=-mN6YIZ*MsJ;{=V{ zKI9zX@5=)8Fu^grIeKUp^dz3{&V+EWA?R9iAA3K&s1)?^ZQ2{ptG(wdpRR36(rbnI zaNt^txSea+gR#hGD!YDp_MYlJs4;FMp#4Jw=28XD2k!Yki8@NXU>YL1FlctySSThA zBuVhD(wsu9Z3*p`H8tZ?OTsntK1hP%N2b5Kf7}y+a8(MF=>m{%tn-2`q`Vi=4|}A@ zvurj`_#HySlls_yUymw4ZBkR8Uzl3PTha2C&Ajfq=Ef5wGozhZS8_kM#w!B{ZE9`? zyRtsk`ru9YPx!2U8`JlB9kS7}by>)&#OkFbws^A{W(ifYXM^1vCh7AJnZ?jkn77Yw z;^z4>zgS5%Dg~Ed9a&0b0m~C`ukdnU%sn`G2{c^ESdU}TRPS1Vu-v0W1yfmAWczqe z_3gs>=-~#r$U@%J*oNao`ZBEw_9!vn_(K(rtTB55V``n@j!+!ZMG5e0Paz+vcZGfuRCqUKYtE%Q zfXN;p^aq=9&`ReO>c7S4*nb;2r%`d>0o{MCw1)Q@rQVxn{32E`CXIOg-ot~Ep8y9S zgWVpHJwNqycQ2ibx;SJJyFcs{yhCsLu?u=g1KfIoBizPhCSht&Ohcc}UY7^uFF19L zPnN&?yEo{ve2*~G|IW!gr&RV=#B@MP&1;flI^LyJf@E2GoEEQR-A6#IT&*b&lO2_t z@tQ2{!yI%hG$>LorW7S_i%8L*SZ@S7&Ns-VJv*=k0UBg3rVLfS#QFAiJ-PI|QotvY zH;bu6W|7Xx{pd-%tIz7mEF(4E!6aax!b^9Lr8b&ww%f&Urj!NTaDeGO0n1 z?`m1ra(LH?4bT>T<9fAX(+^Yv{z!#%3IAi8a_Yac0aKsj4i9+OC9yE0^FBYmrR(P5 zjOa>8>tPQ5)5KgnNn!E{IXL$RJ8FOT7Hgo`JRF=0`(>+p5%G{z`y5@F?XPh;vUc=@7P$q48s>i+EYx5!FsS^At!uE6rS0B%F| z`e$*PERFMVy8hCUnax$lC8ByHsDCjh79YI47zFn4v+ZJPe+14n$`1u)I%sMlrV)8B~iw|>0;-2p6YRT>&HGJ`Rt1;PG=WxMW6iJ>_!58QS^GBv?dyE8en z1tr)dPV`tM7O_!+wmybWN73)Wo}*|^Sn+m3qab)NYMMtTR^mdY0sTmeO;H3N3Y;{R zn{>=B&CJPtFKU*Cxo8Ch9a@W=M{`qHfu~5>iKsZxU;tMdK%a}3O-I~3egEFVQ$S7& zem!`0E_$c@zc(a>D&ssA?9X-eZzkZ131XPO&$gD1y6)^-TE@N~tB`q-sn$14w0Hc; z!aDiDf8Q%I8^bDI*>e7J8gZ`qc)YGgDM19IqW7 z^psgXATM03FHKG)ahpYMQhqEff5Qs1W#Xw!i0DE2LLTl{iFX%)igun0F{F8WZkJ@o zJ|Id8LMh7Uk;6Mrhhvsc+R+aWdiGq9c8*gn?!x);7A54`uE>ak<7j;9D$ugDmtw!t z%8^bZ>Y|ja4VOVM_gjVsjqwk#ylKeh&&@0(tlb4J1Z9@h#+v~rWM6Y+c7drdJIy;m zk^tROusy+7^8j0QbdlToHCfxF_4*!9wo>MmOy_l#lK3l7wqrK zbK4eyuotAFJCy+B8GWCX-g%2~5S83Nasy)3JTo-*1=4#!dT<+cARS)Z@@pa8qnLC% zIPsb#QpJZ`H}{w!EYjlgVp)@&)=gUVyv&Js7W&ZchlaZ}a zt}Cwd_Zwn(b7rTTR3|QFK!P(h@RvErwjrK%yjj`WO4rY@kBkCOF31Gr69?sSeSw#? zV@vXg9>YJ6zWlAX{BlUDm-W8Z(GDpymM4>Vy<4*221JjCBKA^QatL;3mYL~H5!f?k z*)Z^3ONPic;Qt}(%>SW$!}edcB3Z_yLSoE}8QHTZTZ7pwGp0ghn+hRB_Db2tKAU|B zGZpYM9IFEN)p{((Tp8B2A4<$*L z^yWVB^MJ21j8sVAA=C5G5=z-`Z3Y%)D~8sCOf|1A`y0FrZYs3c9zE0kq<*+3%QJEN z_ceq@Vo7kB-EoV$t_fl^?Xc9OLFdnkO0x5*Y>|te8jmdDLG z)ARZlDSbL>@iFu1PxqrPjZ#V!Iq~^g9=j;Vy3P|sG!3O2uy4}iwSF|MdQtzcp>~5_ zmml_b{#*9T`X=lntKY7_-1&?*B}$XsMkZTh{@nc6y3gVA9$uuV+wn2W1_oK+oCZkm zgmiEdB=~B@32QUK}gh%#pKK!nIOjvfrv7#BYWOVT= zCdN1a5d(!g| z>s{-OHG-XI{_U59b$)JuU<5w(U!N{FI$`y4`y=kbS~~iv`0Ql^pd+jf?lac}j>w8P zzIQk2+URMi13 z8a}di!~Z{RDd=oZ( z(=#=D)1`f+vVkiGnSp61^B-}f^%?D;B99c@swH0``JME1K7W3m1bWn>Pnz28LyVx8&uR|{^>7%k16 z`TwO{h^0?{-alA(TvMiv9HdBM!W%C=b;!blAtbSvd;fWr56d=!1QpIpYJf6}Cwz^i zuBih|vkDbQEu*gR81R-C!`MY~Jx89O`zA7USsH_%Z&dqIA&oC}_3D2rne&jgjGw08 zv^<)Z5(!V4Dq|)`{U`D`((REY)||SJZv#^i_>-lrT%GA&pK&u}-sZs@#9Ibe zWeW7VWyg+DH=ld(;w7ZY{3CCEedz7`K)JMWv;x&s$wBSGkC(u->L?PZ&Gss@%4+#C z8v(xYR^ekzmbNEfstkA7i&Dth1KmNuL0HU`elm&E-Q6fe@Kf6YcW4 zAQnRZ_I*`))rpG<#iv^fjPj0fuKZ@ zF%xwKtu&qSpRJ&nwjy^2ZH(Te>UL6+D5Z2UjG*M@Ko>F8yoj2Yqq`SzuHwD)5B9_n z-iM$A?CvPIQ6)euM<5kngYsG@8gc)uE=`}&MD`y6+b>nnG8|0;Egi8G+zJSY3^s+fujos=!p) zr)A78jeF30Ob|+$Zh5}SS5R?F(Vka|U9KSIY!N@Jp-Qi}D4MGSUULOlX@Kk|3^n^7 zoX6{lQ&`)(@0T?yv=Wm_mw^Bz1IB6WL&;a1TB`Ek$Jx2LB4u7+Ao?+U>Blt;`sxTe zMR)MgeJ$MWN~BM{fTBpIw~>7LUxW^koYo+UB;Ervw`14UiYwCm6=Fo zq1?T4tzM44=4BL1%jA(obr&WbrDN_i#c|(A@P2j9JQlxEJo-xUm$}eM(`ekIUGN7K zx0Wa27yZM+^nhq(^b=MZM(;A@8}(uh2`oW1S4C>TJCJw&OnQb-*0X}{1P36J(uF#t4xN8MlHPbO1zd={B-?V z0OOCpHN)eED9WBqk{U}93)x89fsf$yABxHbIGZq%;M#NHQY57frr1>|>FHnxDyaZk|M`&Q#n z=6D>$B$a1!MkcOG{*M$K3lnCwagEbcFa77*h^k zm?QAXpw=}sWWcQ?UV>oA!%d@*Xmk$5Cz_W^lTZpcrLN%XGzsvNw^xOcFB-dDP6nta+ z%|F*S9jBiiNy5l|Ahbx_+nnaJaPBe5T=^56NQ4{8kjMJ;uJYMTQF_v5wmM7>*Z}3XsYaO zh(uUmY?4t*wIkXo#>OG*klpeODzQ5w=#cf3MSw!dm#^*M9q^yGPn8F^$t`-Zl$(vJ zZq~QlZ&Cj4c3Kp55BvAMlaV(0{^1wfA@`fkr^{X~V%|1L5G0CI4*6-I6=)i0S5Yr7 zuHSZ(c&>2Vf_gD5<*u#2P}p_UqAHRx8{*DhsUuFgZrr*or-g1(KKOBz@?S#BVg|66 z#Fd6zF-twe@oQR3VJ!`MO@@KD(0-n1Gw6diT9M*9rCd%A=I@ihi^e~vcV(}hL^25N zrvi$G@8O-PGN;G~{Z7*>3V>s=l+!EgcvS9x{nDCjsEn+JAhg00KPM$`7nl&E*#UQw z>Tm6+qY-T3JScY8<@gk|A7;l7^NjR|1|FH7ag{LHP-=KY7c~0T*wiU{+TGI73BCI< z3LfYQM3&hXuewp7$v5|QXIX}vL~w511?!TUD0>P@rW~zsr$j7aL;5Sh#Iz`sdD+KO zM~Hk7dnjKVaXcHF%pDtu06WAN=Q$1*lHB@}8(r7&P2_BVj9V;c)P9;8Ln%xI9W)Db z=>~yT?)F`#c>DpkQ4M-GoXv$+X;yc{h{t`&zETHcHfz$cx38f)6BVkZsRd!b05c4* zXeTLamnj-ZPU60t>7pMwuItqbcd5!8iQv9#r0ljusF%7Ye^+N4vOOMR`f!c=PU_6M%)ksDm~^=Y${DG1^*Y|9&`<0-3MdU zw<`)}dkWvv2%^rOQ(QT5Mp(m?Vdkab^;raG)>Tnt~^Gn8+m1*P8_m|G3QJiz~$VvExQz*TDers}m5>)1pc4nh| z^@Nj4X2wv8 zW}l-%^u94zId08`77L5DC7LhHpGf&tUU;QM{*>d}06!yj1KD6veh!dAT=@ENxJe-! z8=B1Up5D4-PdJOtc21L|js*CkHLgOOa_fD{4^vu~J09{|+9J84*h)`KpD-H$Kg|u* zIk*#XtChVdV6we4UvuDM>6q_ET9mRA1T}tGRtMR9Ht8(Ul@h_Gk8gXWt%CiBq`Qlj8txXJhAiR z^!=7dDJ|z7MMwb>1o#6St}?v9q)u6wFqMTmkQ+lgx}Edr5_ z;=wh2N*L&PGze~a`10fxtFOb27`@8~I_I zj=FMTEi zy;yxn9z(((oyy0tWkKl+B9_8*$+Yr@!ncYA&CyiR$!DZwWZ$puKUJWV>1py}!}V|X z&q#7L*#jP!xeL&Ih}z}!qhRCJ7A>3`E)j`$e-?5Lef?rIx~o1$Z)R?UcrI_?;o^%k zQ1e&%6ZpZqml;^$m^kb$+FPr+&!?a-&LM%a%xWu?ejWzX^|NNh`uj`}n(t>cd54(rF-{X657es?d)4{D8Mj( z{S(akDi%SJmN?SURw;v6Iz}C!%(?lZPiT27y!h+K9)(EFe=XShXruYw`WN6!_Zj0N z8OhAIlK+m~tGK_GE_T7*jpa_#=*VP5Abv3j+~&&duq*!0mj;2+-_~ zFVo0XKZi`^ol>r&24kPWoSK(f#e6LfYJVVr79V|;P-}zvhU263tzw4PO48wmdk2%f zoICTlSyY`GHrnmvzGUQE3I0-V92b}SnR1b@lZ z4D2{x)^jFdy{p-H{@?oeK!9u=Yp#@Ual<#$B?p~XO6Rx%9#@cCRTcv+b^7rgZP(qLQ?Eah9UB^nBZ!0*+iV?;8;5^6_od$u zHn?BV(Q(V1+_>fOmR2|YTIDzu>DduP1zJPwuySMhw4IAlzUUd0TRKYbqKk6k1!Cd` zZ?DU7m#r%eC4Vmt)bd^UZKQZQ#@vxLmy0*fF!{wUM(m^oh?v3J9~Y0&+y{hHT25 zT{do@G~1q7%?eRtrHJx*B-ZFy^Lr-E_l-F^xf7^P8pQn_a-tEAyv2WMKQsb zi#s*Ow9WyHHr>hbs}^xsO}zxZjg3DKlOCKte{ z2G3LvGmq}g<=u3*g&U#=Toz^)pKG5$Rz7A-%{D2sOHP^a*u=z(wgFVGzUupZB=B8k zeXDH#%;MJW|L1kJsFCBU*CsJ0FvX236F?|>gFa=YnAaxe)vN?r^?vTi87c>KE=OO=%OLfYmTThXs= z=zyhOAqe4r{OlvUwLW61xL1t)D8z9vCeuoyxI7iRLPHbG9rxS8v@5(w zE7d^3J9my*aXombCW25NrM?)|24>N23e&C0M7(q66MS;OB|9CiVS|N0+eo1Ci;MDS zOH-4qY@*XQP;i4D#w#9+cTgPS9Icp6D2jQlGympG zd)f4#Z+kJA?3~T)zt@vE+IrrNa$%vFTm9D{`$LD^XbCvy0wKkI#&t%2F;Et_K4-!{ zeY>wfOXc)A%1vkdvPi?rl7zgME$hKneERnrY=IxDq9zItzk;I}W2wmaiU+aHvl7dk zg4bO|4s>PYR^*#DmHq25jZ!j%CfB}FgP{@I&x^YJdgoNuNAaG@yh$B@Bbo`SJMQA~ zgt{a##2O!YNnD$>+Qtdm+}u!?CoSzi-*qXOGhsP~N%^6;b0eH}B@xU|`ekd4Aad8A&Gcznu~z4OVkYZI_~rb}k_5WvLkpuZnR@RDQB08vIZ8 zYAg0vcHupjrNY^6>e}`yM*B$D-}BA_FXY)MRug5pfwXH?d%Yk0P|OIzx%=nMzt9U{ z??HcJ*J{db?4e+frWDJD0Ug7jME;A{rx9YjPXfV7B{^DV+S~28KR@j8xjz&_MEl)6 z??J>~l-ogH|ByL9sAlmmsz&$`+Bxsh$>oVKTpb&hI-u*d=!0U+-ix@aoZPM$0$Df^ z$%K-{ejkiy`u#X6H_1pW75pxGTaars{om#vM-uUNHa~?0aLgq>vb-CgbkdUj)7h(7 zbPA|biMLb2O|%9{8IyBFr?YR^v4*1rWz9FrLte$1EY1H^JzI8YXcjAvKTF@yU7I$R zg?YKyKKs!iKa}_nB|;e&yV@A%TI`fjVC0P82tgBo1_5c$FJADT2WUp5B`JFLIJ00C z)L6>>g>O=t^|Nz3yW0KXZ$hu~BESo2yaJX9k>7!lI3B_1Vy(z5Erqvk$=Ok>l2!}9 zVbqloB43hBh!Apwk|*9L(waT6#jl;kc7a?#RV|E62Fu0GouOkgEZbkHAQg-606s#Qp6C9;PmA+%{k}FO$+w+3kuDp=MCjQjhpd9% zNlf9cbMaqhMMl{kOt78iaWLfV$GtnI&@*1nd4Vuz9rAaN>BJu@8?sWqcm0R7;i^R= zEm>SZW0UR$GbK0HaVs_DG)}p#`FOP$@MjOs*7({cj-!s4BC-h~5F{|kUu5ZT@5J992cu{I z8W0ng9@yC~-igL}Kjw_50|jX69^K#!ZoY4<7J9R-8CiE297bF`ewF#5Z~8f`h^P)! zFGBeEZ{6wjzy$yMKgvvWFJ=4C{lEsjaJG>O8(h!3r~G)a>&r{tDi zeNbH`rK>1q@V;oaL9o%0k{#;-c^h0z-iozZH)i&NR6JggJJuodq+d&5Z~%GNo@gm1PxsU(7VR|-)b0+U(rfij{`RAR3$DIZCvDrUT z5#hJ8f#MgpM`@didV~uN&=ow>HLr;dX)2)20y!HBnPh7sidkzQLkkeYjw3uw6~SKfZi12N3SsE5*)QpgYFEa1(kJ=G?4T#4GD0 zDF1V8i67tZ5lYZhAp;5RAZJeb%M^=!h+k_&NGdkL$fIoMrW~!c#?QVkQ#Znqi{KOF z8nDaVB)pbwr%6O08b>i3U%}|qC5)@jt#{rhNkbbI*(HDP;SEk$oR&;jxsB4iR5)Oa zE(Qk*SWM=@=3d6^-I;}j5un9j@ga~gKC(L@Zl)X`LeL!VB#J-L zu#!KA6N8IXCm1RDY8=DgPGEQ+FFjw$@j*Lk5dGvd-;m5hGfN}PmOMFZ)8KojA0gR< z-$Tc}yXQimOEQ8pQ1(P@nqT@mYbaN>?T(fRdk4K)Hf z;&_He+&<__dwuq4EE|7LT1*hiF8x5kX^Kv^;aMGZ2oYM4Fzmq2dp^ccb0T#esazdQ zI4lmr0bQ+S8HGhO=Vf@>C+V$;g!2W)f`b9a1lK{@(av#|S}~ZoW)NdnV#0 z!i}?avUJWP+9{1yvmTDm<|DY~^`jWqE1KNPGDC>@&$8!q^=G>Cq`tSYsqw>Wgf|Yd z-5=7M|2&!C8636}&pzuMgoY>A+Spb(X~okB)pp)2-~9&P?q54ywpNn468Z%mH5%W? zuZ^C)TmAg->2x-DO`Ma z!!ObI^e4k+cBv}WRL~Tfp^Vphy}epa44|v=10LIY|9j)K_F9)H$lN|qgQnh`aD&TA zb9WuXt2;`SIlcqMi`5Ev@0=TsfdmehGmaL)4)dTOD(m9;w0pI~D3Sq`88fXye(jut z-H;hgVk%+73%mq>AIsb1+z=>zs%D2Hj&&neyHcotbC0m5c)z^BGMdWO>960%G_FA* z1f_!-kz`>}e|5pDzvp}Zt`9^M>eZocuZUtb6Nv0m_XNi1jX_bt7mejWfY zds(ClO8G9TxI^T-fK3WciY!D$>Am>=ios(Z+V@G!DnGO5Tej09Yu&}K;?iL8%Hu%S1?udj)CT9(etQ=ZRD!6Yz-B8YVVr3gw@TJi(dZs75<&K zfYX)EFNckFlp{2iA%k{LUtiwX_&q(?s?KAkc*(uWBb|^4uoljtvCq&o;kh@a!eO{@g4biH($IrF3^-i#FK^tP;NIU z;#$XHs1jQg)a@`n1IvT13NnG0a5j7G7Z^#t)`^!tpO^Z`moamJoR;}gUQkBx_t|!%REQOLdOT%bn%&Ew{5Mk1KV#sQO5@jenN8zDBJ1>+co{F1NybO5VSo zyE(Z2Q1wgWu|!$4;xSU#^3QodCsMbD7O9kttk%j=)Nij-XK#E`aPc(khwqigAbsWB3hb^d+^*e4y5G7a ze@-ukyjzuuW7G5jXuf=R<(7lLRbV<;{Kg1T#r*mBnkX`(I}s@w5H<6H(&p#G zFLCa3fa``gNkxDTrh?tkJ$b}C!B@ER0Q=LM)|g-?3L-^UsuF$w`~oxMj#J9UjrUho zT>8Tn1xq-41&(}f=g6O{lAZA`@kA}!)F{#d~evrJ?@(n7P;!*8!;`(z8UK=>M(Ba{qX?er4;`M5xs#W zVqOX04?YflqQm=oBohGYjdsFIY|eB1Lt4GI3|Z;k*>XXlu~WIClGomr;1mGD+ZQ0l z0#Eo2=Ov=3+Y_Vkm`zGhqG9{CaD3V_Q`kx?=IUhbGgByvM$`=@R=)94pe?k-tXX02 zE84bdt?1V`Zr&%M*fwpWy91c_G1QkBrjGZIGG%Fk0ofg8Lq}bYTy{rA9HG$)mD!55 zz=J0jREo6r-{Dy?7$%qpsiFO`egI7&{jpc(N9EH_(d$2Wy5H=nN5t9oVZA!=U68gI z-vD}Y544L3t_vb2>T`?v1?|HMhs;s$S`ZTFl9aht@@};*9P#CCj~DRVs$b=$*bUNG zwq0^8-MmByoP0FqhY6r~Mi?_wp6=eSN9MKRAw4vdW6g+vN?z0oUH0piOGZ3@cOcq? z#)i$NNRMq_N1dMR--l=nhrywgkFG;yO_;&czCPmLI6>TR?4JzVGN#Df(pv?)N1TmAN1((HB5z!PR z1%35rHcjhLM@z?_7(e@os(Q$gSHo5oUx_M(zaH1W(YMyyHg1m6p!8k2FbujIhXz%N z{--)PH)KX?x|@3G;)_LwPrE{PjQT(ThZJX?rt9gjBaD5YmBPT~iaHpEblnfZ2P(!w zi;E9+SqtMfVw4{lsMmJemqFfKb7wOyMAK9*;hR#i-v9---m4JYEy>2tahL3HTGK57 z*|q3p&H2e_~MX$PF^{#jTV`>)|jaTNeRu@FD3TAb*NA{Ty_D>~Qnp3pUi~acRqflxk zq&x=0z{AaDA#P&J&{e2CkM&)`-T)7^y^L=YKyddQ?*=M`Ex+!^L`$gHNr2I^0Yq_h zz@veCg%&;e*X+jJuGC{Kt)eC`el1dJu|Gs~n)OlD;6fFLHOViik5>Qfj zPb@?&S-Dm#NUQrg-*IUF`|tM-mBUNMuVg&(T;8L~m?riA_N-u*P_RuNuEn)}YkOs{ zFL1Hl-GQp;Qsrz!(=%g&fg4Mf1Nd6#U-+ z#z7}c7K&n4d$*%9QIgpVHRT+B>7=S>EQfTRyD6N6Sm6fL{0&`$k&7=o%Xgo^i=V+b zUXd1I#sU!doCOqB#M2Fl$D7;OUY_}^75Sr1Eg^ZUfaB?-GC3$D-%|Z5ynh>jRjLpw z&ngVDJNvXHKQm$eKKwKUBfp&e>dc5BYH-C;vDCjbGFs=gz7k{O*@LH)+jsmjM|QtN zJk_gn<~`N+M0UC^*8_0;r%cw0t9S+tU9IsYa=D)2YgNQBP`KfczKiz4dvOoO*>~VY zK61-y={Gq`XbkxYy=3RugSDJH2Z zH;q358b<9-9*^3X7l3?+B&Sx$aZ)@uR#!B4a(~?^PC?gtF2hn$s$c8#KK4nq8dh0g ztPk}!r7^~qg!a0j%_Za%k!)C>W!X_3-_AY-Heaq7!Mzcc!8H}DoZ_bFt7wxrA<0s} zp3Pz6W7#z%?eYsR`PlT;f@;&*QWxv@>4jDqXoo(FFTuMv*#V@$-saKzRP6PLGz^5( zj!~HOwPd={sx;IWo8NRDZ>8yejZe{Nbs2x~p(Uum(i|W0kbw}NvO5z&c@}j|?y`0^ z!(+`JC=AUmBKt_~nd*f-?De~ZN0?e;5_r`3z zYw!{-+Kzn4G<;Vyx+nyylxueYrW2<_heVY$IBR_AZs!%D_|IGElH2z27Yk+&UENE@ z^zIve_=FDOl+wP6q39MBr*SRwr6Lw*xHv?&7%CsOi%=#vz=78TEcJ3tIe zLmRD)S);>dS6(`)nL>{VMKdU64I;KOGh$Ib*VQ`1lZWcc#%?l{+mBqiB*TWTYZ>p} z`)SICxmf(7Uh5n5oQha`z1G54pyTo$TnRwcqtd}q;f)=BH{In(E6;}G9%3am!QsvQ zSTX|i=@E2`cRBy+RF)upp#||+u*?Kr$!j-~kj787U3!Ih1i3ov<(nTv#-<2<)m;B5Jm7Xu%@%uSC=9y~wRJ#aV z)iS&KYHp-=wRxS{z}&@L`(@{(L7N#Hz}h;Ao}=&SyioYfMF3Yo_c~8DJ4^5*{Abme^i;yPGcy zO4oZUFB+)K7mw#D9;Q`$oGF-O__$n=rS>GPd3=nypj)dc;|4c_TLkbMYd9UI+Q-n< zwhu%>wL9CvAv$wunW%!PV#ZN)1i`DCn9+brNG!62cgk+LehIpzujc^tf>RdQDqhP8 zK&2Z)7zn^4#Us~Z(lLa4g>nou#=0i^U5ytY%BY6Ju=kg)ty8Ax`9VY|7RS1JZ-=#GMDTKP!R?X?(( zDG%-bZ2Ye5O^53>b@QOP0qvI{&w!vw9*~qrG0Qd(Z_uHmRJ$E0$hrCt2?Ln$Hb;>-H%T&Gc@++q8zQbTELX{ zxP${wat2du3qU480L!AZ2veFOKXpcaV=m6h;CQ2S*~>um+^_mtv5LWzX)8yM1gpxg z>!tvhhODpW(l+3Vj$5p?ALT#!m7UF-g=j}1hwS$oZZ~q~YidIca!=f)x+`!lc%0_xN- z5M402F>@$;L-sEcocyA@M1}~uTL~nU%8VO!b7LCNhKIO)#$}e)O~@D3J>LG7%N1G~ zt1nB$DQMMu1jDUbIa{Cy`7hVhsrVKFrwC-@-&-}DL3vb;+?83kI=mgLVE4u)eD0WO zq2*_bBH(vODa0e{-!UX_Dqh+MIc8@Qa9xX8`jk>`l2{wwMchG?wuDD>5N51R$}!2> z?z8%B-*90>GWzvy4FX`!dnr5~qS;34@YS{Y43vpQ!!Nd-K&zOr-MBV0qS?5A`yfi` z1r1G-y8qnyzGdFG9?&mD0;neEZ-eoN{`hMdR#M9Dorh_sHKQSr^LXAWkSAg2*??ly ze-Hwv8UnBweV4~H;n3!R0La+xA87F}Gn8D)1cRV^6iAZ49h05FP7ug6Gb|zHW}r2r z89=+JEKiX38wt6T=rX+5x%=V|Cj(NnYFaL63M$N|uDr(co`PJi^K2jX*{u74^Fy zUP1ElJ>aOfDCb&N33!4hue{Dzn7fHk)DLdvcWvkisYP)$Usxf%GE+V7zt-HuZ}yd) zm41?F17#I(UF47Zow)GtkP^d+7mll-)i<%?;fIhuiezs8k|=w|?PpX;wJpbwpK?>f zp&8d|0!6RArMB)Fs?Fo-TjDRvr`fjWXY`bwi3YpPZR2k-K#3QxOF`~a5UM@l$>*ND z#r3D71qC3EO1e`TWS|Q{>+%M2^PV6bZ66OI$NVvqQ%+=Rg*R?#$@U7?V4DahP#@VP z%CnsU%&=rC^7x)K2gz@hFb7kN`Edza88VH8c2fD6nV9~EOjqnWy zhCYYgf)p{BK3Au{9yMj?J?3^EYyw!@jbothb@usJT(U==tLEL}W7+nSMKR{z#BK3x ze(NmV>A9?2@Q{f__Mg4s-aC@VmCd@&DL3hdZvXt%!EI8q&`thFpaNh_-6p{OI=b_T zNHxJb@77Qlep|{*r&MY~3VyuPyP1x~c->9uh?7*0&L<>}-Qh!*WJrO%Ph!bWj)>Lr zfY@`B9Mqrx21L9%30&n*U{EFgRm_c4%iF)UDF{vc*cWbso95yJMhWz6%j(UctT*j+ zB)fY!-KN}+bfntWv3u*oAGzJjzbS8<^HO26`w&5$>CHoZTj<5BW8KBxk{2DM98QMC z4UNcqMRR;EhXNJ8zaqw3Rap^i0yu)Wh{Q@)9Pv@HBbW6?kvuhslcCp9dRq{FwmnY+ z@W@R^~Y7sCK# zIUe0o6Gb*%%X{yh6pS4o-)=q>w8TKz#98>T{o!} z8zq;z7Zj zH5tIlAf(MZ8E!zB4VJt%oBI&U((R}PCj97&r}w|6)G9eraPZdC#VHOFKr6Au%hH@v zA=9$6_mRxQXn9-jM{!&C;8xj;VD1oO!qHTYH6uW>3*u3EQ%Wir5bIc-&jV zEMLB1XUYbs37_*@KQ+^#VBtDN%aSisgnceFCb85S>*&U~Tdl?JI6V+!5o?FI^9SPz zu%H@x*rgO3C=N23Vz}x;ty|!X{x##ZI253};8s0k_{h+;QfuorTSW+e_KYIBusqk zjmD7a%>G|5diR+d=31zHLgCJZ=wWrzwel9JHCEo_!bzTAiD1c22X?GOcf%Pvg35;` zO(^bmK_X(kJ+26)cmKPrLXG5bRHutY&X9U+roK~858xcPf5kj*zN zB%g|*pogp0ag_Wt1I609=h1jvc$tDBo70zS`&}(#wOm|)a!-0(nfZJ#__J#E9zT`1 zbbyb8bnM*xqIRZE2vU4Qj`R>MwfITbeDrS^fLv&FZ8U}oYR0-7o+SbZvLkc2M9HuQ z;951l!eLWftKHWoKgL=}Oam0`lsGuAaj`TL2Np>GQ6z5tGg{^JQIf*mX&#JlwS9#I z9%*p7h1*v5YTX%yhLAy`D$;IuYFji!C+xfzK*Oxv7 zuz$;n24`jQ0dD_?q+S9_S(UXH+q(hXz{eD?f*PB0L0fUk#X(MHOnmQt^?L~Z7vhA4 zlL{NkpMrN*(oAAljaR0i$c^xI7nNoL5B5|nxF**W*R!qHwkSY&WK)C>3YGMgMChxZ z(T%kcBLyBpym~xjM13o!qctIzqjrnpcc_#E5)O8;<1?32ktc^<3W)!P14uDWA?^_P|OxfBhn(&iO7vKV3iZ8*RynbOR-DEy+hH4}eHuNG;`b&_AxJY5Gr z$BM#w&m?T$0ehmkORm{<6<3uL4Y~0f%vdJP2aDJMw!$yqBCk#JJA5|r_wS$0MAweJurrxGU>_my zaizm0b!>Cntjs?AqQ@ma9MyieDvk$x!Qd7rN|Mi+lHjhwhr_wlnD zmV&;*5x}MGP+0G9J7!Ani+_-Jzrayl%qgX?!MT_6@ybo@uGV}JpO3-g6&7in!=(2^ z&W}|Z!}^;NTRQ0CSAOfcs=glk(cA5poD#m>db6*DcyFK;NV zLhOpRwih>+{KG!0=I}gW5Da9>AEKb2QiZfSV}?{|&-M?OGtz~m!FYK)@^iTbkWRJH z=LyRu3tc3_ws-hV}#7o)6AnfF<^Ti-AJ8ry^sskW9!OAe9;u~*ZWz$x52Lb zY3dnKdF~A-LwbocY=CP{m)>4X^9rU^s|XL!bSuIy?U~v>qUQmd+oZ4HX8D?gx9Vdk-LO{zn5b2otfr_Ix^&uSN6&Wk13a)(^x%}ihu1{mnw!%wOFh=7)l@B z_sg)$9k{*?Vt=p5kFEbKq1F4oNtz&O z!8rG0Az9T4nlDZ3@Dc6vdycezJTl)$eAw?{E0PDMGvHplwmT z9Q;6%^I|HjLA3y4))p?rXIT<9F{yaJp`*1+PdV+v`D$JXv^@#HIxkU*pz0L+ zo1LOkZVpX=DNpWubR7k|D2rfgh}=@4{^E68#%|v1*MX;!%D+F~E11TX6Z95OoW5;r z#$|*RG1Lf}j=hREnnr%P9Uk64qZ9?cpjm|XI-N;bx_t5xN&|rg$HZbz)*&@xjYr4S zmBXG?Iv<9DGxYj36n(uyVEO9!uu8t{)MAo|F-I<$V?aVU7U7SS9W6AhOTJ%`()rR^ zdXOPiU-k0V0vOF0QwG&;c>Ozi>&g^&t&O_ILlLarq#S=6P*_6S?UR;(A?I!8s)9$f(S^E%Oq zXiZnU-*`EVqs*Ouz1vd}mojV}rz6&^{xqPV1|FtVoRk+@#_RoAXDBk!a_&0{b<3PX z`Zd%X@<1frUCs+a9r?gJ;s&><`L<0V1QHVEOHN{4Ns;qE@pws`Fj;Ft7=5yKUhG!L z&&$+vAQzgo%&Zmw<|g}HL@)5BP*!M6G_)IN)9HtX-sUkjXZUl_B}YFhzZ0Du0@+gIkh6#!h!Rsw5G{#WVCCugdO~{GERh0hgrU&i4!)sLm>i5VR3fF?C3=AEj-F5 zv1I!?t5ZR`plR~K|5WwfQB5^pxUdBfP!R$sqEbQ<2%SjpA|;I$B29{5Kq;bh=@we( zgg}V&5{eY*2vQVj0Rai10@9mcL5k7@zVrU>UEf+a|D9Q9=FFZwWoOT`_p{TIcBU0Y zLb7O3Ft6`)wEQu${q?42a0mWM&RTUE@3vi&f!{>lDKvLLQJhCw6A27~Y|T{D?){gZeH;d9@ce{iw_dQM zOJc@P4jf8}G{>Cc~!vo4Rt4J)Q|CLI&9>1PEbcrPFlTQ3M9-rJh9e}d)9B6F|!|f^~ zP_*lF?<$--z;qs7gCFDf1-?o?m`xH;bsb=k$niPPgttPuNL9MhAD?!e#$>NyZnpT8tr;%S|dRCTzCeX%Wv zw~nNtWO6s=A(h}~*;mLDg)Avn8c9Y8DYOA@s`z^jPNfBhwJ|8>~UUC%O$xPVXTD;DOiY) zbvN`eBpk2w8D2NprBs8Yl@}JjE{tDb%$l*$8eZ>Dd&T7@-^emiy|#RE(6dy88*T0t zBU;1U)9ZTg<0_P~S?-m=_=yIS^u9dL5o1;;>(m|*%?MGfsEHPRUoilrtYt{*u-|}x zhe=q~@&#cxUE$8Dx>;%ATnufp6x!!(bT8i4$55!^dz&Kp=IL5wsWJAp16*8BWkWP zY2wD7xY7|2bbsrpYCAN{t|RUG*Q1uYaFdw!7a*hrc_Q4 zLR@N>@#X?ZBI5PAz!{0CP(GpcUU`&NtmBsW=!xz;=TuSMF{wGE$_KuEl0uo3e~egGsdV4m^H3J?wd=suyd)Gu-S+}rZju&oLg6=|o0L4< z)6RV-NyL|sE0}X_obQHq!-*-j$8Aaz)8*@P4A6nLmv+rt;l?DFT%>65sifXdhB~Dd zn2PLqU2ZcFDivw!x-H_SjaqM!_tJQ0#f!4!uR==ZLH03e4z(oumW{O`ghm=>R{WD6 zK0)?e4ZNG&-3q$X2b)SeML%t`52pA2@WGGI{))hT=#JNZiHyHeJ_A-RLo?E`6?YF1z2|Kswh6@E7H#v=ViBKGNMrO6BIGo7|? z!W^@|Kdy?ols$gpN!*_0zJ4;P57Gmr7Y@wYLNdVbbg64^!v|c5g?)uj#7uMm2n!i} zF5dDNrH?XrbKHM{mSVFxH67HnnCqhmA<2W4Tbv96FgL2iN_9;~T-by(I=)qe+!FJ( zTr0;zXjt)|Lzu9$Nk_0m_oH7ECEGjaF=0FAZ1$(cedF(5ePm74ZMcE&hL$c?kpT#C zdgT_jl@lc}lmGqO8vn)8OL?4kVlq?aM}zHM46`eZG)A6^+!S|tYR3N*l5DhtS2ZWN z-ihi~?SbZN@G*Wf8ZAint`>i&K8|_DLN0D8w(**~cOITJ+}d>>V+}cj zw%+4@O&H$mZQ(Zc+^XagkCv>xHPOIFB&75xy}t#HCXv7}`bC0U~E$y^y5e+g3tw-uEd8w%fVk!)b;z5H?>Mazd~3L0r4~F@`wm z02hAo?elNel@C6iv8Mkj5o^rchxO{4pI@Id{B?pGk4|}wi<(AIk-AVvSrh;!@l%G7 z&?nHzn__PUR`wn!r2+pz!6hI$d2@d3mvc*OO*-@rTap^PF39*Swdyz;*O7IHRir>p zqCP2dfZwr1D(wO8;w?6ZF;5hX_D;_@{HKkyoESBUwX;*DZ9~k-PP&@p7#-yUIFwzA zoWdbq<@v@q&LZ}r1gz#`Ga=}zHVy=d(Eos5g(tBEkZ;f59`al|Temu3Dm>O+kkMlk z4+n5F~gOX?x-UwLYyZ0-FCXjNHgI0=@~ z`@Se1ot0iAD^{nWKI}C4)SH%p6Wmm^55YC~avXuvO}z#d3(1S-)-a%mfSARlP9_PNHUo9&MGq;SL|(4U@rLse1Bwz; z&bA}5u+q+tWEUbdWs&PUJOA)+K1CEv@{Ed`k!P`yp-ZRfTxZN#k#{~1Yu>F-Jr~o_ z>JjnkK&5@ztT|1J&QCJJFb{zr@c(;PuMMwc0$u#{VgUP#}birVCSWF)wCw@>%k%6csXMT*+H7fLn0h*o9s&xze>Ba zKP3S-?(S+Kr+$OkC$gN zgGTN^ZF!*-6(pWQ$dQF0mXt>Y_xG>tT}bpy>WxvA_O;9>B;$yV%qShUyRCs7vG>Jl zRwp@t3ssPD-_zBJ0OC{lcW~3({mezaG=X-|Z0Ks5zPeQ&rv+A~1N=L@5Et_t1Oa~) zJ&B9?Jbl*^cVZPl`CU7iU6Q+YE)|vxpe-VswvzSI&I^oP6tk)^@~BVgj;SL<@Q#;f zdqqnZGt)?7Co5%DpGmtYm6D4b-?w$g;l=18D?)GV9-f8m!23Wfyf}bW_%r%NYR@%F zU_t>30Cm-{R-S|qom53iJty(;r)>^*o@3#tL{IXuKm@8zu6k5q=#de2sh>5>D^`U+ zK4?8_$7L{2%*y-oQ)1Ea6d`$m^yFnY&fJt-`7;L@0U-RDZ=S?8pErOjA8O?<9zZNR z5O4sFd}`z=DH!(wZE21Zvx1Cli9G@VOzoulDJARKh4MuQ4))=#w{q~Nr*vM=6^+pN zvzZ=ek~vSOFgtwpHY2jZzmT0a{8p2V<+(m-+4>X;{A4c}8Mi{+9UpQbMw}L@xihiw zak>Q0CVIhrnw{?Z4sU|vgT(a%p8_}T}_ ztYguzMM-vKrSfHKbIQ=nuEUI5XmG)@?$Tq z{>%0=`rWH4zuuj(&n6rFpl|F@f}7*9-w#ArN=8{Q=7(&RLN#>=(eq*sMkw1XQk518 zmLxw;{^~Bm{RDTa&jEEInH?H)X@-l1WO?lcxRm^WO7JzRS>FAmLg$4#;Z~q4kZZQH ze!0X__zni8FPh8aaJ&EY;sA)=*W9Nn#L67J$;R!Qy5V@w4lrd2cy9z+#n;Z!#TLVw zrs#LyPT2G-Yay@p&nfweaBVOB{65HKnyMI(aUg1X7x)-cQp*8HObL#-a3$O60}7bc zruVtIkDT9?SOE2eU(U_4tx&2KJ3YME}%4AB$`YZ-sTfcb8NNlUya@`KCqx?~ywQ3fd;P@AMuzRlP5 zie)O-^P0-}c_9&cN)*m~E;PQTxG`+xX)gJ-)pP7Ku`B7|mo@h=iPfLhPvJYBmS8u7 zP6WylHuwz6{`rw2wAq~=rD)K-Vhvt+eA(HJq<#LN*Kh2pXJ!#@nx5jAOl>8A45Zvz z1lm{y7!`Aexa{3GQ%8qfl$iW*XAZL1v=rP-2L;U|yr|YM?cC3NVxR+O=BKU3`&$&M zz}bo+jhL@88a-w?EKVLVg)W z=;BN7G__9FRhCf^rLMWQ{%aXPAD_Z%qaj(5NL1n@^XgHxhfaQby;BI`E}PWlU|l!y z8bh~}w8p=4;Wrtw#BgmfF4mAh@pv1#Gti6h#NS^Yc$e}}u=;b5aLWgq?AH&@n{o0u znaQW3*;xn5@hDh{NR~-*_?PW1RQt&)(jhNLhY7e;Uakc!^~u*B`gxt{?~IIROl(5i z9mc;%w%8LOi3S5kfmYwrRi$7y&l<>uSX;+ml+bx0gW9&R`cw2Ww>XgB-!hRM=Qw%AOXIN{B}kk#vQvix8@7Fda?6UqU{$_RAQr+t#Yy*MlQn%- zVCU~94Ei3gxImIlteLl}=0qWA=t2Tny>+0ZP({Y@aon5v%tbV8oQYhbHw<@@rs9+9 zq_`!Wy6%nGGn^VI6_&J^`ONScf5R*0tqVRD&gH_dCAy3c80z0`Rs@kw!bWo4HFTR=7A`|E`hy zV!F)#L!8niG3Acx;98zEK5-|apm|^nr&nOU9z<;g z+)yN{C@SDpL_4kN`-bJJHHXi&6d&w{+{t)FQ+Wp)*^|)3hkUg-(W3Q`O^x6H%g{9M z|BLj9Iy|sA8_QxEQWU83>kGrxV@T_UtNC00cK*w6EY4_^i(;)tIi> z%(N*``s5`aC0O*?G7sg9df!@vlA`HEIblK$B~X!b=Bg3qu_2JT8kvWOb>&OVj+nN* zkCbu21)jWTXcgx^S@k+)M6nB1lOC9rf2Obd^0G3qg!QIE=sB|(8(}?Z>m3E%X6Lec z`F~uM>MvMh9b56@xqUF9MGjcJhcOlj!=qglr%ni3ti0Ah%b9%e>6yUo*k!*nGzW77Xsp%uV@BNvj13|n?V#SvCMMN53Entu z)f4qve~%INN^LGh^2!Rd`5&9}%cYR~5t6BP*Sv@*?I{Vfg@fnIN)H#aLU7ZlvRJ;z%?HIe)hVfC`EHqSVB|E()?+ zvh~(wFOdzD9dwfoMr>NPI1)W}qiQog-k&9_H-VoSOl?P^u2TEjBh4+Q?vP#XS$NMt z%F8L?vZrpKAx`SRvj=@50cL|NkETCOhJ3)W$#1Z;dW zm&?aOz}cGH`3wWc5v$?8cyWidDMfgQaDhRE>*{NAo#YlH<9^w(OqSSn8E9tOb^_M) z_TZxp?bUyCtxcUnNskgX)c{pc&&?z6dj8qs2x7nF?+dW4GvPz*ugT^h zwjA+$g}Er{Jof`RC%5Fz&2yB9)6kYRVGb+Lu}Js3pV{ce+sStjB^qy4z+FKr=acp& z-DDNsC*MqIA>k9S4F&+5%)o@vo5$F2sBG_Q%JO8BA1Du>%bqny@S>ySf>8lgR=?|l z+ZUNf_K(JFya2|K;jfP|`AeGc{>$(X_G^Y8IFa*W*Mwq11_w<6@ItFS$Y`-~gn@=g zw>CQW5{``YA%;jEanpqAZ9XCd;pHe!eW`Q}m@A~x`+YDE(8b(NT=A_0O!f6^d^N2P zM9l8^GJ_7TNmto_~AaGlSb z_c8n{kO18bpMvb{aNr#Kv!gt|I0eF^zkczv?BGko?rV@IQW|7?KVk2GS0cYiv`mVU z%qW@b*Dkd@rJWSbW9S_jE4!u{jBe$gMat6BU5}6D70?hTcBt_qLU<~=rQ0v?$ zsg`Q~^gmVV0BSVRl3Fjl4z906cVZ84boOw?{+K%Vy7J2u%@iw*t_UokOr?@SC?yuE zz8bP49vc4~X#=M@Ix%!$EVO$8gfw(2eGHT!@DwERGT>Q?;VtNke0t-L89(>U-EI;# zrts5H@+Is!bmQZ)7pGey3Wofas0e@ZuJumuPQm??$ww>(dhrX8{ zy>y)w%NEHzT)o-sw)V$|?FBBAdJ6hEs{j1Zi$p4GtJB;tpKeSnEYVvLp+DUG5K7^5 z9&b6PcdL;Ph?O%)Kc&ZkHSX;=JyJ%y6VvrP!dORa0IN4gKKzw{lE|}c#@F!u3Kn_x zXxp<^vUkBu?^*5>(QIA6?AaJt!{XV5N0C3MSqYM{>@>7ko^ITdu(XxDX_eajK-)IS z|KT_`SCriY5-D1ELrAqGCb|d$gy6^3DMNo6dlGU-1?Mly-+-p;>WIGgq=%!mOaEpD zdkj`VQr|La)e&cqPPjs-gDK@bNE`h;V>shMgq~bgp?f&UgUjexi6EY8iAr_%FKPvU z1pEdauX%QOD7uXoc)rvf?i^UKh;~CCR8sl#kv+fnc67h(H|~yCyrp_HEGG^a^jk?w zz*1`*Pm6N%MCd?yDwI3iEqScuDKn?o5WL87ZKyy|+?U-F(T0ZWvQUNC_C~-f!HJ&g z;e@5Cmn*0YL7kH99DjBgdh;o|A5Y#-lW|I-)X)f%ur4-5KcfQk-rUXZ_-IIPCxJ7*)A{kQa8`H+~+NDFQZJwb70F7=%XhP$)6n9^yjR$f-=SCU0niZW)`p! zye7B#TmNKV&+Hnpc}1}#hhj@92CqkO&psug(~+*qk~g3nkIJu3IcCo`{1I&NVJCrd z;qK_}JITNH;t}_~Y}Tp>n$KWJAhiE7;AwLYTz%kcf~HSoE$&lKz~dX#sVkPBc(o=A zMP!oT(d@-KMNe`1MdJ8o9{m=@7JuuGGLLg-v?OoAuGw4}KeWZhAcHFKV46vVH>gZh z=_UTzEf)Z2ogy?psCJDlIUfhVH4q(sAXd@8(L3)!rJOU>B?d(B6zmvE{^G8W@SofW zg$bpo!ma*pZ;Z!QwxsmacDTqkAeW;XuL)t1A~!faM3QV~;^+E7-mO1dIxCbC1^%wv zUkm;G0EqP8eP!;T+aInAwrahNzKAx$NESnZgV81qGs`LlXMrJ*?BSNeW(9)MrUP~% z7pMf_N)`p>7V8qTiWs@N_zX-Py#l+ESBQqZ80SG>^kp&V6(^A#7*co8=ZTpV1`YM* z!Br~h^OZ9yI7o89P5dt>J*GC%kZLY{6?T$GvcWH@(lI9n8~k} zw?9kJ3XwXpVh27;I8cAzS${}>fQw_3B|;bEasrx9!3dQyJ+pY3_~?SCoc|{dbfxXC z`S#U?`)E2rFCE>WicmPg{o+gScC0q8ZX;;J8h~dQa%n1Vd#%2U0)O~~JkEM}TK>CD z00ljM5sUIg!rtMD`H{94Jlm`N7I3|buXV$b4!H0hfImb#Mu+BL<__eov3E2fMx^i~ zPZ{VjIO%OBF`|0hl_zQPSsA2ljTS>Q#T$hXjhl?_!gP9!G-ZqCKV1w_2BGIntI0p; z1A(sXYVY$1LGCJ@(DJab4|@-CjG6FWO*b^x4V94j#ddN;`MJ14IG=n@Kx~0}|Jnmk zmPSScF%RFj*5Dm0U#y^;iapdXo$)bydSO!F%iB*?F4B#Or9Lw3(2N_y!dbdFE$e6c zU^Z#qM&p+)qF30WDUEgFCa)n7g7(zK>;#@~MH3}HS> zSrn=<;n=Htiq`EHZ05aU2r^+4Lcwkdc)nQ#pxq{7v5w_C(*)r9fc#avV5+n3E-6A< z8C_VaNB?$_f7ouY@dQ!Sf^h?It2Y2<3Dow_!c&yN#d0M~AHgX!MQOt@GKp(trgJ3k&&##W6vy=Z^^>=o46znLR1XgrHKBU=JC!ajofC=i8_EB{l zt}wLPu1h79f%IQsj!z0uJ>(0MMSAfN!(=@>xjYU`BLECx%VKTDv57quQ5@8N4*PpH z%YDQpBv^?ZqHR_jDw+LnOsXu$hoWO-+7%a$-Z+0`i*WImPAk$YqP<-9a?#}ccEM9J zZ?W%j9clHzw2cROPNx*$e`?*CPJ)u#LXN9U=spT*hEzP)gDM3klHORHodk3YNHK6m z;uo_SS%nxOOCL2w#j5w3I@_$Zgx5Jaq7y*rC$r00<=^F7-Ya6sk-N1lZNwG&YyPQ_ zs{;3i1mFvkm6J791hWBVZ|8nEYQ^9b%k8T)8n1G)Isd-HBJz0>%GJf+ zOIW|+ed!>GrUoSXq;fg$7zdh@l90+MlSnLz)*G}DxC_o@GP;bH_RY~6--(Y(z@!!4 z7~?1*i?)g^(n_qokA6N_PVnr!oN!S1I9pc6_M1g2T0R*HwvI2BzILvP%i!IqkW=p~ zjAcX_<-XD}8CmJb@@rRKi;(wSo(MUvgV3+>Yuq|Yxt!Y@leEO`_k~8Nh$Is)npQYT zI8^>*XF~a(0O9u|A5fYu-GSBNd%urdezqps>(C&PWveLy3;Xb;v@VkKKZf8!mFwow zAuf-5dbjq9Nb=za%#|hqK%XhwRA{#Q=WnGIhPp=H>XPS4k`gH&3f=&wIKE@o9WF4; z)w~5_OToV1?RcpT@@Sb%b}@h^KDzt95V+BK`7;UcP%PDYo55As{GiawuGw@*cvQ-h zE)FEN{pL~nF8Rgrg#&n7lFP63z?WxB@1G>|3@f?q3Hsivy3&*EZi?Q&pmpQ;n0Nhj zq&45{iBqlLZoL}qlq_@@XMtVdkY01tv2{NSizZ$P5CKp#&wKIJK_7c^6CD-hZnYB6 z*_+o`gStepJOQ5{OeU+)Kct5bnjaKiu;>K!5X3c6LP`oU4kTCTHG%zE^M@H}EGgSL z>?p!_)yIZ!PiJzZwd@SS2XmZWJ~4pE<7B!HvSj2X(jz+of9q7*sNe6NT|J+|dvUCa;OmGZMc0VXUDs6x)6>~Q0;Si^{P2FT zC<+9^O#7zb!2@(JwbZt+=SmQShE3k)?$eAK5Hsx)`wy`WO2Q6&J;*L_r9?h^Mj@hE z3t|>shr=YJ_d(7z%O^Q*E?cXSeX2+Cj(XP|fV1~cT^)|=vEFkwkqj*4?2^{PHb+Ugxqk7=gw5_$d;uSSYaF4CPd2u6r?Y%Cn5DJ#r~QE+k*;}WgXmo zYZg`vXbX2U&$}E5rKU;mX}umnjE~MK;U~-rQ&6*KR$l*xIt=9vWbI(E=r;DFnISEt z$R9*1XHl$3YYBw>$jR=F9ecj`v!WuBOwb6^e<}LIMJnD~pvWJNrf97HK_k@mF~fzAA}c{m*{y0ABOGPcrAitF)5`9#mH zP&PLKVZh|ssVn@Dom%A?{T{3%BU`EhKfG`EVweCv&buIAsu9Mg7HbZ``*>5tjN3J( zLBkS{>&C}c&zngoQ6X_+F_EXQiZ;g?sJtJ}lU80f&$ty|^TDy%Or#ABc6wOrMsw@7 zGV^JWLSQiNJ@}e@`TeAZizXdwfk8?`{@03g3`pnJvLlN1tbe5$*k7<%<(|P*>lELeh`U@q!(98Ag7|4V3P^>+T z)p6#LYsNpi$5>Ia!ZJhhdPkma3j94tA>;B2VCwQ+mTmgV|7Y&JyQ|orC6YR0O1gMG zpwuoiIBS;#{jMY81~*{`lCe0yWurFjg~DTGI*;BoON6Z8q?f9r59%8qaMP1Z-aj) zd=2O?_$GnPm*g|ew%AzNZ5-1Iqdm6&-I>%$Xu0J_s)oy4qf9czUTcrk}-1wR@Q#`o~!Ah-q+`@LgPaL zD50(o3*I)nryjJZAi_tZg6(NqL3F6oJqAjvp}*0pCQMfB})n= zw$^T+S~h~7MG#MmTfwL-sg>~<$l5Wnc4zJOuqwRzH%Pwul5X^QN$Uyq;ic&V>NQ#G zRa@?QOR~=6>=7}^TkbDcOylYa4|nHct6i=&VHrE+9w$)7;&Wt0cSc~Ks%Cprje?9S z=7@*f%Y7Jak)2lVb5Rmn-=_OkVm+y(Sw+S)Y0rztzT?X8g~*Z}O1HPjwn{cx%>4Se zF8Gxk-Pz`GSs~Ij`LrQY+y#LW)YVaGrFz@pKHGDD%*7?UWX{K6mDiLVx{YAoRH%SJ z2rue3hgbR7+d|P|C~|Sf63F|8twQZ-I@-!r+cPJpy>Qpzchk6hX)=hqegg7UFdoTs z+iMV@>J^8nOLh*PHkW>mo&L+@j zaHc3l)eHX9l6$uCWsV`FGNoegxZ3o{`!^IXHs_OF=vob5tZc&+I!X+o^>@W-B2u(P z<}qIGUuRO#>0>md%uN#M)=-y6fzT;R%3>y!2yjUrR}|HTO>2maY;`5n?nzjkjuqQ{v3q(H4&7Y zL^a+Sx^^<%50U(03zx!X2Jw}JBMgwxmk74tDwJy0{ckeU3iN`%m_e`63Vm2=0GqfJ z8!VH!N_D=C-z?s>Nc=0vR4vj4N+IDLlk-Sw1()$^mt5jJ#T^c~MM$e2O7pHur`B}jYts!4?ksXE>WJmk z0uxLFBZ_+&)@AnfVNLY83?uVY=g<`YUlb#6OMaPK%e&4R(etsh!c+XyG8M-E!rtut z`xTAmvqFCn2&tf(YUj7yhNpuc;80=?-x4zy);N`nJuT%qyaaDBHl1pS3Zg~7qbmV0 zF;0=$0N=-4fxGW$ty)1-oMp;rNF%7uXl1(~WHb-hCBO~olaFi7NZR(5a$)4urg6Kyc9uKv7FVAOqv(o^wU*ZXb_n*`d* zGaFfiu`e+tTj~{X;Yw9&w{fFMi?Jt2qV`um?qJrHdt0vz*{4(ZF-+%=q^$X@St1#n zJl9;%{N*GKh&oe^QZQgI-NO4~@m{;~S@A4X?ALU@PWHJUEq(TQ)XL z&ZkUHuyHYnteKzg8KJ1uZ#kUT8AaKdl<<_BIDMFvZp_t*IE>}1%RRGu0b;0J9zuiH zGw&`ngy4hR@X+zi7b#euPZl3_jr64jk^JZ(G+B5g*ZGxyNC+6}#}m*r8u*B<=+?&= zZd8@V?y<7JQuoy0rDvL9F{dKTJ?$K=!OL40K2vosrZA$RhZzmeHV1TjHbmLdPSI|W zVbtZ8Lggm8>w0%w+8VYG4F1h<{q;;;(knKO`53>jBW`GMvouO{u{`{hP9(B-?fmYz zCy_a7FaaGtKxK(SB}xcVUz`91Hi(Z{FkhvL4H;inWns5@2%1cQUF`S)Np=ZSkcM+( z5|GDQyJp%24M`^$NdENSVAL%6l7ppsL#wkFT<43^4YR>ciJqd39k#__ zPhpyCK?2GlXxjTLs5H6j3Mq^y!dZF5eBkO$bp`qqlGPxo57T5uCB8m|IqDssfS;^) zE?Qc2E@vnGwZC1qZgpLcaU~aZaXh{~{E7_TE{YLR_^V48El&OH<9xa7EJ>%h`9s5t zi&{UFzdwvATr&_DL=eOk}2_U0Ox#8}Gpn&{5jgZE|%!4|}$3EF!; z`-hH5=qJ_yGBT%E#i(6)-<3Z2dOx*U7p)_nrQ8+LbUbhM%gg>G(Wa%@$NXYgKEGO& zVc`yX^1Ph1*YuB2xZEBj-6L*;S+p4p=webhd$?N>^fa@O2* zrGvThhvOfdkN=Ka_y*is*Bb4=tk~l5N*q_DAJ7#0d3(4r0F|)kr~hDDFe$h>RLSl* zN$bs?N2skmsa9)=vUPikN;y2VTuGnd# zjLaYH%IQCgHJ)+1={+mz;LC<@D3gOT*=i5-T_{Pi8t734E!*Y(_#pf2xFU_Lp7@dP z54F~1P^KB`%VV~G#`g}>Zt7QipL;xbb46t_>&e6HA+_V>ea$IB@9cK{lppI+BV)Q3 zzJC@}n+efakwEG8!u15{lqm@7Xg+?JM}^qk34LF#lL>30JZtU8bHu`>!OpEmztD+2p>8 zxBTgyHMHuZIu(?b%D%KUJx!iCT*@>m9$A$=zT0)+=@>KHA@WEQc;4RYo8MXLTTe8* zFead+oHMfO(|p4bTaFpNSURN!G;tUw-4E-V{ak!Va;lnu+CKqW8Cqf4@WlO~q&2wy zG?mKc-||sy4T|cHO*?=-rAHblJa+v6wESyIP0AWham^&V{q$A{_+QyzYj8L{_xn!X zVvb~e&mq6M!t$z5;0gz^JI+sar{O_P8Qtt|wo$SF`t^)=H9cFHcdqqAQg#2Q!D$Ul zHFA7EAQkom{Zqhob2J?gKqE-r_W^lG=0Tu)%l~a|NC37R=CbjRbTS_ogpV!mR?jk8 zpS&CG2-EKOUYCkm^!dMK)2&i+kR@vix#7Nr{C6WVSAA5oere42oA=cx)LdxOe*S-| zPMsf?4AU|?X(pzrdgmF;IOom3^yU5P<0C+9r3=+f5u3p%A(p+_WWRQ6H{VuVZ)#|^ zv0mF|d(rBj)}qx{SzEwpNZVc)TQ-eRwnqs59v<)#3Fa&C=y=#8^ZK$N&#qT3^}h;~ zRYC6Iup-K}E&nwi)et>`BJq%v*pQfgyJ27U>+z}<{9lM|O~%|sKMlKw%Vx!60bjEi#f#o>a%&nuWK$C+2#9Z$CrMn4AdHd+wU%H z=N%oC?Y#lS70_6_w6v2~@-8>^0NN3Ck|tQ$zT(Sfp>(Eja^tbcl|B3-7l(T5I>~O@ zANBA!An1j^k+ItHIs=#|jgEgv^Lw;&<^gT8<(lUr`VW;8W{$SEpo`s)zw{P^6FUTp zFQxAvR~!Weew7O=24+q&{0mN+7e=(J6_CV&IQ`g2sBsL-gHscV9EMNzK(q2mTXJ|lZ zM2n`#I>qn9OaU<1nrCaCUKmW|-r*V}0Mj+UB(|f%lSbUQdUrN65p4EUZZQs}fs;t`oxvOw6yn|UjpvC|9g`Q@f0~(-4U;$~=4nF5GZxLL% zc}qOeI+)Ms$XC6)0e*C?@jsn!d)amz>@gDd-uS9!CCu-_|Nj*Ys4Yb>^5M&9?}sT1 zyFJdDynBqT=E62Fox<+&{ZEA4%>{Gm04dB{TQ_QP^?&Uc1|uKaY1_eSahT z7h~V^X0q(R?y%Z_f^PZJ0ZHy22>{{-4b|ZCf~O}laBtefFWenHE!6XH;jw?5@2a>~ z-+x*Vhydn5;=`nz#E(1wNt^{p9JMDXF`dY5#&k*GsjM7tk5`YX#Y zThaEXtl=v+!x4v`!~dq^|GU@Zc8%OSQsn*9uy7Re-4~eX9~xUMh5lEzy~zc8UO5v*3ac3v z*m3(kN?M-*Is@UqKC$|BvLU1rX8d692pF3ocb0yEAsObfG0n!0^QG|rRhH}mJAGfd z_2PtheNYMA>}H!kF#5xz^`@Hbb*t4IuD?f<)~A4tEIs|0*0qIUiAMi#U)(%Y1J{#Q(~68ak86Znj;z5{a=a#_f+j0;_2!TIRL|oc6p+tZa%#H#2Js z1HKVyHgbl#D3Gq>=>j}$bM{x*@UuVVTipC_FMn}EE)nI4T~I=-kR6zKa`S(@^{<}#YQm7h}fzWwjv-lu@1 z{kQo{;(!8=)UGaVq*#WU_S^b-{?}z@U(eV}>-aAb|9z?To>gf~{aK8e^g8e^N9^4a zv#50a?=}BPvz3|^YH#FtV)Q2EKWUVZ0^F%86X5@eMsebH`t4Rde^T_h?U(-!rQ^~? W&xE8y_5KsU52a_MTd8yB+5ZO!8Xsf; literal 0 HcmV?d00001 From 67f3eeb8329fdbc9dcbe56a2ce160cd2bbf40138 Mon Sep 17 00:00:00 2001 From: Ronald Aveling Date: Thu, 2 Sep 2021 13:04:46 +1000 Subject: [PATCH 38/76] Changes to global header (#6452) --- docs/components/Header.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/components/Header.tsx b/docs/components/Header.tsx index fd626a47d71..32c893a6aa7 100644 --- a/docs/components/Header.tsx +++ b/docs/components/Header.tsx @@ -258,7 +258,6 @@ export function Header() { Why Keystone Updates - Docs {/* TODO: Add in search for mobile via this button */} {/* @@ -277,8 +276,6 @@ export function Header() { */} - - + Date: Mon, 6 Sep 2021 16:15:17 +1000 Subject: [PATCH 39/76] Update `website_live` with `master` (#6472) * Website live (#6340) * Update index.tsx (#6278) * Fix updates bit on the website (#6287) * Content management update (#6282) * Add Wes Testimonial. Cleanup. * Typos * Fixed whitespace (#6283) * Update Header.tsx (#6289) * Add CTA block for Web Box eCommerce Course (#6273) * Content update (#6290) * Style fixes (#6291) * Fix styles: CommunityCta * Fix Styles: Homepage * Stylefix: Wes CTA block * Style fixes: Why Keystone * Style fixes: Content Management * Style fixes: Developers * Style fixes: Organisations * Style fixes: Prose lite Reverts text color to default `--text` var per Figma * Style fixes: Docs Home * Stye fixes: examples CTA * Added new content to /updates (#6300) * Update fields.mdx (#6304) * Fixed typo (#6322) * Added top margin to docs page component (#6301) * Added styles to table (#6315) * Added styles to table * Update prose-lite.ts * Update prose-lite.ts * Update prose-lite.ts Co-authored-by: Thomas Walker * Un-nest tags. (#6327) * Fixed link value (#6328) * Update `website_live` (#6336) * Update patch dependencies (patch) (#6253) * Update search config to match new DocSearch config (#6255) * Update dependency/apollo client (#6259) * update apolloclient dependency to latest * changeset * Update dependency @graphql-tools/merge to v7 (#6246) Co-authored-by: Renovate Bot * Rename first to take (#6266) * Expose stacktraces from exceptions thrown in before/after hooks. (#6263) * 6268/next typescript config error (#6269) * add typescript ignoreBuildErrors flag * changeset * Updated /updates with new things (#6272) * Check exceptions returned from GraphQL (#6271) * Lock file maintenance (#6277) * Allow bearer auth in header using sessionToken (#6276) * Use Next 11 in the website (#6256) * 6223/custom pages guide improvements (#6264) * update example to include helper components * update docs and examples * update docs and examples * update to docs * more updates * changeset * correct incorrect props in README.md * update smoke test * update images * update example * update tests * remove next dep from package.json * updates * re-add schema.prisma for admin-ui-navigation example * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Apply suggestions from code review Co-authored-by: Tim Leslie * update docs * revert change to next-env.d.ts * Apply suggestions from code review Co-authored-by: Tim Leslie Co-authored-by: Tim Leslie * Update dependency eslint-plugin-import to ^2.24.0 (#6285) Co-authored-by: Renovate Bot * Fix updates bit on the website (#6288) * Include stacktrace flag (#6267) * Remove `gqlType` option on `autoIncrement` field type (#6280) * Use playwright install-deps (#6294) * Update patch dependencies (patch) (#6284) * Update prisma monorepo to v2.29.0 (minor) (#6292) * Nested filters (#6095) * GraphQL API docs changes (#6297) * Update dependency @types/jest to v27 (#6293) * Ignore generated files in prisma-utils (#6305) * Move import of mergeSchemas (#6310) * Update resolveInput error handling (#6316) * Upgrade Next to 11.1.0 for the website (#6311) * Update @graphql-ts/schema (#6312) * Lock file maintenance (#6320) * Split create/update field input resolvers for relationship fields (#6317) * Expand editable area (#6318) * POC - Expand editable area * Change things * Create cyan-rabbits-look.md Co-authored-by: mitchellhamilton * Fixed import url on CustomNavigation component (#6308) Co-authored-by: Tim Leslie * Update text filter API table (#6330) * Update the tags in the docs navigation (#6329) * Update patch dependencies (patch) (#6331) * Add a GraphQL API upgrade guide (#6281) * Fix issue with VisuallyHidden checkbox interactions in table (#6334) * resolve CHROME BUG * changeset * 6261/fix delete alert (#6296) * refactor confirm procedure to only add success toast on success * new deletion logic in Listview * add crud-notifications test project * update deletion solution to be more pragmatic at scale * update bug fix to be more verbose * update schema.graphql * minor updates * fix yarn lint:examples to not break when running more than one test-project * minor updates to copy * remove log * changeset Co-authored-by: Tim Leslie * Version Packages (#6199) Co-authored-by: github-actions[bot] Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Mitchell Hamilton Co-authored-by: Tim Leslie Co-authored-by: Ronald Aveling Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Mitchell Hamilton Co-authored-by: Ronald Aveling Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Tim Leslie Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] * Website live (#6341) * Update index.tsx (#6278) * Fix updates bit on the website (#6287) * Content management update (#6282) * Add Wes Testimonial. Cleanup. * Typos * Fixed whitespace (#6283) * Update Header.tsx (#6289) * Add CTA block for Web Box eCommerce Course (#6273) * Content update (#6290) * Style fixes (#6291) * Fix styles: CommunityCta * Fix Styles: Homepage * Stylefix: Wes CTA block * Style fixes: Why Keystone * Style fixes: Content Management * Style fixes: Developers * Style fixes: Organisations * Style fixes: Prose lite Reverts text color to default `--text` var per Figma * Style fixes: Docs Home * Stye fixes: examples CTA * Added new content to /updates (#6300) * Update fields.mdx (#6304) * Fixed typo (#6322) * Added top margin to docs page component (#6301) * Added styles to table (#6315) * Added styles to table * Update prose-lite.ts * Update prose-lite.ts * Update prose-lite.ts Co-authored-by: Thomas Walker * Un-nest tags. (#6327) * Fixed link value (#6328) * Update `website_live` (#6336) * Update patch dependencies (patch) (#6253) * Update search config to match new DocSearch config (#6255) * Update dependency/apollo client (#6259) * update apolloclient dependency to latest * changeset * Update dependency @graphql-tools/merge to v7 (#6246) Co-authored-by: Renovate Bot * Rename first to take (#6266) * Expose stacktraces from exceptions thrown in before/after hooks. (#6263) * 6268/next typescript config error (#6269) * add typescript ignoreBuildErrors flag * changeset * Updated /updates with new things (#6272) * Check exceptions returned from GraphQL (#6271) * Lock file maintenance (#6277) * Allow bearer auth in header using sessionToken (#6276) * Use Next 11 in the website (#6256) * 6223/custom pages guide improvements (#6264) * update example to include helper components * update docs and examples * update docs and examples * update to docs * more updates * changeset * correct incorrect props in README.md * update smoke test * update images * update example * update tests * remove next dep from package.json * updates * re-add schema.prisma for admin-ui-navigation example * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Apply suggestions from code review Co-authored-by: Tim Leslie * update docs * revert change to next-env.d.ts * Apply suggestions from code review Co-authored-by: Tim Leslie Co-authored-by: Tim Leslie * Update dependency eslint-plugin-import to ^2.24.0 (#6285) Co-authored-by: Renovate Bot * Fix updates bit on the website (#6288) * Include stacktrace flag (#6267) * Remove `gqlType` option on `autoIncrement` field type (#6280) * Use playwright install-deps (#6294) * Update patch dependencies (patch) (#6284) * Update prisma monorepo to v2.29.0 (minor) (#6292) * Nested filters (#6095) * GraphQL API docs changes (#6297) * Update dependency @types/jest to v27 (#6293) * Ignore generated files in prisma-utils (#6305) * Move import of mergeSchemas (#6310) * Update resolveInput error handling (#6316) * Upgrade Next to 11.1.0 for the website (#6311) * Update @graphql-ts/schema (#6312) * Lock file maintenance (#6320) * Split create/update field input resolvers for relationship fields (#6317) * Expand editable area (#6318) * POC - Expand editable area * Change things * Create cyan-rabbits-look.md Co-authored-by: mitchellhamilton * Fixed import url on CustomNavigation component (#6308) Co-authored-by: Tim Leslie * Update text filter API table (#6330) * Update the tags in the docs navigation (#6329) * Update patch dependencies (patch) (#6331) * Add a GraphQL API upgrade guide (#6281) * Fix issue with VisuallyHidden checkbox interactions in table (#6334) * resolve CHROME BUG * changeset * 6261/fix delete alert (#6296) * refactor confirm procedure to only add success toast on success * new deletion logic in Listview * add crud-notifications test project * update deletion solution to be more pragmatic at scale * update bug fix to be more verbose * update schema.graphql * minor updates * fix yarn lint:examples to not break when running more than one test-project * minor updates to copy * remove log * changeset Co-authored-by: Tim Leslie * Version Packages (#6199) Co-authored-by: github-actions[bot] Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Mitchell Hamilton Co-authored-by: Tim Leslie Co-authored-by: Ronald Aveling Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Mitchell Hamilton Co-authored-by: Ronald Aveling Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Tim Leslie Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] * adding a devcontainer definition for easier local dev (#6343) * resolve label bug * changeset * Releasing update. * Move testing package into main package (#6361) * Move fields package into main package (#6362) * Move admin-ui-utils into main package (#6367) * Reorder access control tests (#6369) * Move utils package into main package (#6368) * Move types package into main package (#6371) * Better fix for list view checkbox bug (#6354) * Remove old fix, and added position relative to content container to prevent misallignment of hidden inputs and labels on the list view page * changeset * Move the exports of `@keystone-next/keystone` to `@keystone-next/keystone/system` (#6377) * Fixed error from prisma when using `.keystone/api` from `generateNodeAPI` in a API route (#6381) * Move `@keystone-next/keystone/schema` to `@keystone-next/keystone` (#6378) * Fix negative `take` values above the list's `graphql.queryLimits.maxResults` not causing an error before getting the values from the database (#6392) * Update dependency stripe to ^8.170.0 (#6396) Co-authored-by: Renovate Bot * Update @graphql-ts/schema, rename `schema` export to `graphql` and move it to main entrypoint (#6393) * Update @graphql-ts/schema * Update prisma utils * Update patch dependencies (patch) (#6394) * Lock file maintenance (#6386) * Add comments explaining that the schema files are generated in the schema files (#6397) * Improve performance of create item modal with many fields (#6390) * 6261/delete alert tests (#6382) * new deletion logic in Listview * add crud-notifications test project * update deletion solution to be more pragmatic at scale * update bug fix to be more verbose * minor updates to copy * remove log * init * updated delete notif tests * update usage of deleteAll utility * update test.yml to include new test file * remove onconnect and unnecessary try catch * comments * update gitignore * update tests and schema.graphql * remove headless false flag * remove unnecessary closure, update failing test * remove unnecessary try/catch block * fix test add throw statement to errors * add waitForNaigation to beforeEach to avoid navigation destroying evaluation context * remove navigation in beforeAll altogether * add acess control headers to fix ff preflight errors * sub out fetch for node-fetch and circumvent weird preflight issues via page.evaluate * remove page argument from seedData fn * update yarn.lock * simplify code by exporting deleteAllData and moving projectRoot resolution * Add `introspection` support to Apollo Server Config (#6391) * Allow support for introspection. * Create great-cougars-argue.md * Update patch dependencies (#6398) Co-authored-by: Renovate Bot * Update master from website live (#6402) * Update index.tsx (#6278) * Fix updates bit on the website (#6287) * Content management update (#6282) * Add Wes Testimonial. Cleanup. * Typos * Fixed whitespace (#6283) * Update Header.tsx (#6289) * Add CTA block for Web Box eCommerce Course (#6273) * Content update (#6290) * Style fixes (#6291) * Fix styles: CommunityCta * Fix Styles: Homepage * Stylefix: Wes CTA block * Style fixes: Why Keystone * Style fixes: Content Management * Style fixes: Developers * Style fixes: Organisations * Style fixes: Prose lite Reverts text color to default `--text` var per Figma * Style fixes: Docs Home * Stye fixes: examples CTA * Added new content to /updates (#6300) * Update fields.mdx (#6304) * Fixed typo (#6322) * Added top margin to docs page component (#6301) * Added styles to table (#6315) * Added styles to table * Update prose-lite.ts * Update prose-lite.ts * Update prose-lite.ts Co-authored-by: Thomas Walker * Un-nest tags. (#6327) * Fixed link value (#6328) * Update `website_live` (#6336) * Update patch dependencies (patch) (#6253) * Update search config to match new DocSearch config (#6255) * Update dependency/apollo client (#6259) * update apolloclient dependency to latest * changeset * Update dependency @graphql-tools/merge to v7 (#6246) Co-authored-by: Renovate Bot * Rename first to take (#6266) * Expose stacktraces from exceptions thrown in before/after hooks. (#6263) * 6268/next typescript config error (#6269) * add typescript ignoreBuildErrors flag * changeset * Updated /updates with new things (#6272) * Check exceptions returned from GraphQL (#6271) * Lock file maintenance (#6277) * Allow bearer auth in header using sessionToken (#6276) * Use Next 11 in the website (#6256) * 6223/custom pages guide improvements (#6264) * update example to include helper components * update docs and examples * update docs and examples * update to docs * more updates * changeset * correct incorrect props in README.md * update smoke test * update images * update example * update tests * remove next dep from package.json * updates * re-add schema.prisma for admin-ui-navigation example * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Apply suggestions from code review Co-authored-by: Tim Leslie * update docs * revert change to next-env.d.ts * Apply suggestions from code review Co-authored-by: Tim Leslie Co-authored-by: Tim Leslie * Update dependency eslint-plugin-import to ^2.24.0 (#6285) Co-authored-by: Renovate Bot * Fix updates bit on the website (#6288) * Include stacktrace flag (#6267) * Remove `gqlType` option on `autoIncrement` field type (#6280) * Use playwright install-deps (#6294) * Update patch dependencies (patch) (#6284) * Update prisma monorepo to v2.29.0 (minor) (#6292) * Nested filters (#6095) * GraphQL API docs changes (#6297) * Update dependency @types/jest to v27 (#6293) * Ignore generated files in prisma-utils (#6305) * Move import of mergeSchemas (#6310) * Update resolveInput error handling (#6316) * Upgrade Next to 11.1.0 for the website (#6311) * Update @graphql-ts/schema (#6312) * Lock file maintenance (#6320) * Split create/update field input resolvers for relationship fields (#6317) * Expand editable area (#6318) * POC - Expand editable area * Change things * Create cyan-rabbits-look.md Co-authored-by: mitchellhamilton * Fixed import url on CustomNavigation component (#6308) Co-authored-by: Tim Leslie * Update text filter API table (#6330) * Update the tags in the docs navigation (#6329) * Update patch dependencies (patch) (#6331) * Add a GraphQL API upgrade guide (#6281) * Fix issue with VisuallyHidden checkbox interactions in table (#6334) * resolve CHROME BUG * changeset * 6261/fix delete alert (#6296) * refactor confirm procedure to only add success toast on success * new deletion logic in Listview * add crud-notifications test project * update deletion solution to be more pragmatic at scale * update bug fix to be more verbose * update schema.graphql * minor updates * fix yarn lint:examples to not break when running more than one test-project * minor updates to copy * remove log * changeset Co-authored-by: Tim Leslie * Version Packages (#6199) Co-authored-by: github-actions[bot] Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Mitchell Hamilton Co-authored-by: Tim Leslie Co-authored-by: Ronald Aveling Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] * Release notes for 2021-08-17 release (#6345) * New release notes. * Update index.tsx * Update 2021-08-17.mdx * Update next-env.d.ts * Update index.mdx * Update 2021-08-17.mdx * Fixed markdown for bold styles (#6346) * Update wording on upgrade guide and release notes (#6353) * Updates nav additions (#6366) * Relocated "K5 vs K6" guidance * Updated sidebar navigation content for `/updates` * Update new-graphql-api.mdx (#6375) * Updated URLs (#6374) * Tweaking docs for Next.js walkthrough for latest version (#6383) * Tweaking docs for Next.js walkthrough. * Update next-env.d.ts * Added upgrade notices to GraphQL API related pages (#6387) * Fixed link color inconsistency (#6388) * Add note to use `yarn` in the embedded Next.js guide (#6384) * Tweaking docs for Next.js walkthrough. * Update next-env.d.ts * Update embedded-mode-with-sqlite-nextjs.mdx * [WIP] Related content links (#6360) * WIP: get well in bottom of page * New RelatedContent component. * Added related content for POC * Added more related content cards * Updated guides index * Styles fix for inline code within component Co-authored-by: Thomas Walker * Added 2x testimonials (#6400) Co-authored-by: Mitchell Hamilton Co-authored-by: Ronald Aveling Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Tim Leslie Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] * Add config.experimental.contextInitialisedLists (#6403) * fixed count in relationship field count mode (#6385) Co-authored-by: Tim Leslie * Add graphql.isEnabled config option at the list and field levels (#6376) * fix List Items API link on new-graphql-api page (#6404) * merge aria-description text into aria-label (#6412) * merge aria-description text into aria-label * chnageset * Ensure relationship input types respect graphql.isEnabled (#6408) * Add isFilterable and isOrderable config options (#6416) * Add seed data feature to examples (#6370) * Progress commit. * Replaced Lorem Ipsum with Public Domain content * Progress commit (task manager seed data) * Progress commit. * Final tweaks for TS. * Update index.ts * Create tiny-guests-sin.md * TS tweaks. Co-authored-by: Ronald Aveling * Fixing the "try the v5 site" link in the docs site (#6411) * Fixing the "try the v5 site" link in the docs site * Adding a note on security and a (redundant) check for a leading slash in the path * Add dynamic tab index logic for navigation on website (#6418) * wip * Progress commit. Add to Header to prevent duplication, needs further testing. * Progress commit. * Moving logic up to Header. * Update Navigation.tsx * Update next-env.d.ts * Update Header.tsx Co-authored-by: Dominik Wilkowski * Code cosmetics in Admin UI (#6422) * Update example READMEs with seed data instructions (#6419) * POC commit * Typo * Update examples/task-manager/README.md Co-authored-by: Tim Leslie * Edits to blog README Co-authored-by: Tim Leslie * Replace graphql.isEnabled with graphql.omit (#6420) * Update index.ts (#6424) * Lock file maintenance (#6425) * Update prisma monorepo to v2.30.2 (minor) (#6433) * Update typescript-eslint monorepo to ^4.30.0 (#6434) * Update patch dependencies (patch) (#6431) * Next 11 (#6414) * Respect graphql.omit in fieldMode resolvers (#6429) * Update dependency @graphql-tools/schema to ^8.2.0 (#6441) Co-authored-by: Renovate Bot * Update dependency @changesets/cli to ^2.17.0 (#6439) * Update patch dependencies (#6438) Co-authored-by: Renovate Bot * Change isUnique: true to isIndexed: 'unique' in fields (#6437) * Remove unused dependency (#6443) * Update dependency typescript to ^4.4.2 (#6432) * Integration tests admin UI (#6260) * navigation tests * more navigation related tests * commit out bad test * update schema.graphql * update nav tests * update schema.graphql * update tests.yml to include navigation admin-ui test * fix tests * add determinism to init.test.ts * update nav test to be a bit more deterministic * update init.test.ts * rename seedData fn and move it to utils module * remove log * update util for better errors * remove unnecessary try catch * Fix CodeSandbox CI packages when @keystone-ui packages change (#6445) * Clean up blog schema (#6449) * Update embedded-mode-with-sqlite-nextjs.mdx (#6444) * Fix styles on document field demo (#6446) * Add getChildTag fn to Inline component (#6453) * move getChildTag to util, apply to Inline component as well * update comment * changeset * replace padding-inline-start with more standard padding-left * Admin UI menu available for unauthenticated users (#6459) * Rename fieldPath to fieldKey in hook arguments (#6455) * Add config.graphql.path option (#6458) * Fix a process crash when createContext() fails for the Admin UI (#6462) * Fix a process crash when createContext() fails for the Admin UI * Lock file maintenance (#6466) * Fast Graphql API Startup in Dev (#6463) * Add extendExpressApp config option (#6467) * Update access control APIs (#6426) * Version Packages (#6339) Co-authored-by: github-actions[bot] * Update `master` with `website_live` (#6470) * Update index.tsx (#6278) * Fix updates bit on the website (#6287) * Content management update (#6282) * Add Wes Testimonial. Cleanup. * Typos * Fixed whitespace (#6283) * Update Header.tsx (#6289) * Add CTA block for Web Box eCommerce Course (#6273) * Content update (#6290) * Style fixes (#6291) * Fix styles: CommunityCta * Fix Styles: Homepage * Stylefix: Wes CTA block * Style fixes: Why Keystone * Style fixes: Content Management * Style fixes: Developers * Style fixes: Organisations * Style fixes: Prose lite Reverts text color to default `--text` var per Figma * Style fixes: Docs Home * Stye fixes: examples CTA * Added new content to /updates (#6300) * Update fields.mdx (#6304) * Fixed typo (#6322) * Added top margin to docs page component (#6301) * Added styles to table (#6315) * Added styles to table * Update prose-lite.ts * Update prose-lite.ts * Update prose-lite.ts Co-authored-by: Thomas Walker * Un-nest tags. (#6327) * Fixed link value (#6328) * Update `website_live` (#6336) * Update patch dependencies (patch) (#6253) * Update search config to match new DocSearch config (#6255) * Update dependency/apollo client (#6259) * update apolloclient dependency to latest * changeset * Update dependency @graphql-tools/merge to v7 (#6246) Co-authored-by: Renovate Bot * Rename first to take (#6266) * Expose stacktraces from exceptions thrown in before/after hooks. (#6263) * 6268/next typescript config error (#6269) * add typescript ignoreBuildErrors flag * changeset * Updated /updates with new things (#6272) * Check exceptions returned from GraphQL (#6271) * Lock file maintenance (#6277) * Allow bearer auth in header using sessionToken (#6276) * Use Next 11 in the website (#6256) * 6223/custom pages guide improvements (#6264) * update example to include helper components * update docs and examples * update docs and examples * update to docs * more updates * changeset * correct incorrect props in README.md * update smoke test * update images * update example * update tests * remove next dep from package.json * updates * re-add schema.prisma for admin-ui-navigation example * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Update docs/pages/docs/guides/custom-admin-ui-pages.mdx Co-authored-by: Tim Leslie * Apply suggestions from code review Co-authored-by: Tim Leslie * update docs * revert change to next-env.d.ts * Apply suggestions from code review Co-authored-by: Tim Leslie Co-authored-by: Tim Leslie * Update dependency eslint-plugin-import to ^2.24.0 (#6285) Co-authored-by: Renovate Bot * Fix updates bit on the website (#6288) * Include stacktrace flag (#6267) * Remove `gqlType` option on `autoIncrement` field type (#6280) * Use playwright install-deps (#6294) * Update patch dependencies (patch) (#6284) * Update prisma monorepo to v2.29.0 (minor) (#6292) * Nested filters (#6095) * GraphQL API docs changes (#6297) * Update dependency @types/jest to v27 (#6293) * Ignore generated files in prisma-utils (#6305) * Move import of mergeSchemas (#6310) * Update resolveInput error handling (#6316) * Upgrade Next to 11.1.0 for the website (#6311) * Update @graphql-ts/schema (#6312) * Lock file maintenance (#6320) * Split create/update field input resolvers for relationship fields (#6317) * Expand editable area (#6318) * POC - Expand editable area * Change things * Create cyan-rabbits-look.md Co-authored-by: mitchellhamilton * Fixed import url on CustomNavigation component (#6308) Co-authored-by: Tim Leslie * Update text filter API table (#6330) * Update the tags in the docs navigation (#6329) * Update patch dependencies (patch) (#6331) * Add a GraphQL API upgrade guide (#6281) * Fix issue with VisuallyHidden checkbox interactions in table (#6334) * resolve CHROME BUG * changeset * 6261/fix delete alert (#6296) * refactor confirm procedure to only add success toast on success * new deletion logic in Listview * add crud-notifications test project * update deletion solution to be more pragmatic at scale * update bug fix to be more verbose * update schema.graphql * minor updates * fix yarn lint:examples to not break when running more than one test-project * minor updates to copy * remove log * changeset Co-authored-by: Tim Leslie * Version Packages (#6199) Co-authored-by: github-actions[bot] Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Mitchell Hamilton Co-authored-by: Tim Leslie Co-authored-by: Ronald Aveling Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] * Release notes for 2021-08-17 release (#6345) * New release notes. * Update index.tsx * Update 2021-08-17.mdx * Update next-env.d.ts * Update index.mdx * Update 2021-08-17.mdx * Fixed markdown for bold styles (#6346) * Update wording on upgrade guide and release notes (#6353) * Updates nav additions (#6366) * Relocated "K5 vs K6" guidance * Updated sidebar navigation content for `/updates` * Update new-graphql-api.mdx (#6375) * Updated URLs (#6374) * Tweaking docs for Next.js walkthrough for latest version (#6383) * Tweaking docs for Next.js walkthrough. * Update next-env.d.ts * Added upgrade notices to GraphQL API related pages (#6387) * Fixed link color inconsistency (#6388) * Add note to use `yarn` in the embedded Next.js guide (#6384) * Tweaking docs for Next.js walkthrough. * Update next-env.d.ts * Update embedded-mode-with-sqlite-nextjs.mdx * [WIP] Related content links (#6360) * WIP: get well in bottom of page * New RelatedContent component. * Added related content for POC * Added more related content cards * Updated guides index * Styles fix for inline code within component Co-authored-by: Thomas Walker * Added 2x testimonials (#6400) * Typo (#6405) * Replaced absolute links with relative (#6406) * Fix broken link (#6407) To copy https://github.com/keystonejs/keystone/pull/6404 for `website_live` branch * Add missing 's in docs pages. (#6421) * Add `Edit on GitHub` button to all docs pages (#6423) * Progress commit. * Update EditButton.tsx * Update EditButton.tsx * Tab index improvements. (#6427) * Update EditButton.tsx (#6428) * Fix styles on document field demo on website live (#6447) * Content edits (#6451) * Changes to global header (#6452) Co-authored-by: Mitchell Hamilton Co-authored-by: Ronald Aveling Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Tim Leslie Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Mitchell Hamilton Co-authored-by: Ronald Aveling Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Charles Co-authored-by: Renovate Bot Co-authored-by: Tim Leslie Co-authored-by: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Co-authored-by: Charlie Jonas Co-authored-by: KeystoneJS Release Bot <69774846+keystonejs-release-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Aaron Powell Co-authored-by: Josh Calder Co-authored-by: Ronald Aveling Co-authored-by: John Molomby Co-authored-by: Dominik Wilkowski Co-authored-by: Jed Watson --- .changeset/brave-paws-sneeze.md | 8 - .codesandbox/ci.json | 2 +- .devcontainer/Dockerfile | 2 + .devcontainer/devcontainer.json | 25 + .github/workflows/tests.yml | 2 +- .gitignore | 1 + design-system/packages/button/CHANGELOG.md | 11 + design-system/packages/button/package.json | 10 +- design-system/packages/button/src/Button.tsx | 1 + .../packages/button/src/hooks/button.ts | 1 + design-system/packages/core/CHANGELOG.md | 10 + design-system/packages/core/package.json | 4 +- .../packages/core/src/components/Box.tsx | 1 + .../packages/core/src/components/Center.tsx | 1 + .../packages/core/src/components/Core.tsx | 3 +- .../packages/core/src/components/Divider.tsx | 1 + .../packages/core/src/components/Heading.tsx | 1 + .../packages/core/src/components/Inline.tsx | 8 +- .../packages/core/src/components/Link.tsx | 1 + .../packages/core/src/components/Stack.tsx | 15 +- .../packages/core/src/components/Text.tsx | 1 + design-system/packages/core/src/utils.ts | 14 + design-system/packages/fields/CHANGELOG.md | 11 + design-system/packages/fields/package.json | 10 +- .../packages/fields/src/Checkbox.tsx | 1 + .../fields/src/DatePicker/Calendar.tsx | 1 + .../src/DatePicker/components/Adornments.tsx | 1 + .../src/DatePicker/components/InputButton.tsx | 1 + .../packages/fields/src/DatePicker/index.tsx | 1 + .../packages/fields/src/FieldContainer.tsx | 3 +- .../packages/fields/src/FieldLabel.tsx | 3 +- .../packages/fields/src/FieldLegend.tsx | 3 +- design-system/packages/fields/src/Radio.tsx | 1 + design-system/packages/fields/src/Select.tsx | 1 + design-system/packages/fields/src/Switch.tsx | 1 + .../packages/fields/src/TextArea.tsx | 3 +- .../packages/fields/src/TextInput.tsx | 3 +- .../fields/src/components/ControlLabel.tsx | 1 + .../packages/fields/src/components/Icons.tsx | 1 + design-system/packages/icons/CHANGELOG.md | 9 + design-system/packages/icons/package.json | 6 +- design-system/packages/icons/src/Icon.tsx | 1 + design-system/packages/loading/CHANGELOG.md | 9 + design-system/packages/loading/package.json | 6 +- .../packages/loading/src/Loading.tsx | 1 + design-system/packages/modals/CHANGELOG.md | 10 + design-system/packages/modals/package.json | 8 +- .../packages/modals/src/AlertDialog.tsx | 1 + design-system/packages/modals/src/Blanket.tsx | 1 + .../packages/modals/src/DialogBase.tsx | 1 + design-system/packages/modals/src/Drawer.tsx | 1 + .../packages/modals/src/DrawerBase.tsx | 1 + design-system/packages/notice/CHANGELOG.md | 11 + design-system/packages/notice/package.json | 10 +- design-system/packages/notice/src/Notice.tsx | 1 + .../packages/notice/src/hooks/button.ts | 1 + design-system/packages/options/CHANGELOG.md | 11 + design-system/packages/options/package.json | 8 +- design-system/packages/options/src/index.tsx | 1 + design-system/packages/pill/CHANGELOG.md | 10 + design-system/packages/pill/package.json | 6 +- design-system/packages/pill/src/index.tsx | 1 + design-system/packages/popover/CHANGELOG.md | 9 + design-system/packages/popover/package.json | 4 +- .../packages/popover/src/Popover.tsx | 1 + .../packages/segmented-control/CHANGELOG.md | 9 + .../packages/segmented-control/package.json | 6 +- .../src/SegmentedControl.tsx | 1 + design-system/packages/toast/CHANGELOG.md | 10 + design-system/packages/toast/package.json | 8 +- design-system/packages/toast/src/Toast.tsx | 1 + design-system/packages/tooltip/CHANGELOG.md | 10 + design-system/packages/tooltip/package.json | 6 +- .../packages/tooltip/src/Tooltip.tsx | 1 + design-system/website/CHANGELOG.md | 22 + design-system/website/components/Code.tsx | 3 +- .../website/components/Navigation.tsx | 3 +- design-system/website/components/Page.tsx | 3 +- .../website/components/ReadableColor.tsx | 3 +- design-system/website/package.json | 33 +- .../website/pages/components/button.tsx | 3 +- .../website/pages/components/fields.tsx | 3 +- .../website/pages/components/loading.tsx | 3 +- .../website/pages/components/modals.tsx | 1 + .../website/pages/components/notice.tsx | 3 +- .../website/pages/components/options.tsx | 1 + .../website/pages/components/pill.tsx | 1 + .../website/pages/components/popover.tsx | 1 + .../website/pages/components/toast.tsx | 1 + .../website/pages/components/tooltip.tsx | 1 + .../website/pages/core/alias-tokens.tsx | 3 +- .../website/pages/core/global-tokens.tsx | 3 +- design-system/website/pages/core/theme.tsx | 3 +- design-system/website/pages/index.tsx | 3 +- design-system/website/pages/layout/box.tsx | 3 +- design-system/website/pages/layout/center.tsx | 3 +- design-system/website/pages/layout/stack.tsx | 3 +- docs/CHANGELOG.md | 15 + docs/components/Announce.tsx | 1 + docs/components/Breadcrumbs.tsx | 1 + docs/components/DarkModeBtn.tsx | 1 + docs/components/Footer.tsx | 1 + docs/components/MobileMenu.tsx | 1 + docs/components/RelatedContent.tsx | 1 + docs/components/SkipLinks.tsx | 1 + docs/components/Socials.tsx | 1 + docs/components/SubscribeForm.tsx | 1 + docs/components/Theme.tsx | 1 + docs/components/content/AdvancedReactCta.tsx | 1 + docs/components/content/CodeBox.tsx | 1 + docs/components/content/CodeWindow.tsx | 1 + docs/components/content/CommunityCta.tsx | 1 + docs/components/content/EndCta.tsx | 1 + docs/components/content/Intro.tsx | 1 + docs/components/content/MWrapper.tsx | 1 + docs/components/content/Pill.tsx | 1 + docs/components/content/Quote.tsx | 1 + docs/components/content/Section.tsx | 1 + docs/components/content/TweetBox.tsx | 1 + docs/components/docs/ComingSoon.tsx | 1 + docs/components/docs/CommunitySlackCTA.tsx | 1 + docs/components/docs/CopyToClipboard.tsx | 1 + docs/components/docs/DocsFooter.tsx | 1 + docs/components/docs/DocumentEditorDemo.tsx | 3 +- docs/components/docs/ExamplesList.tsx | 1 + docs/components/docs/GitHubExamplesCTA.tsx | 1 + docs/components/docs/Heading.tsx | 1 + docs/components/docs/Navigation.tsx | 9 +- docs/components/docs/TableOfContents.tsx | 1 + docs/components/docs/WalkthroughsList.tsx | 1 + docs/components/icons/ArrowR.tsx | 1 + docs/components/icons/Automated.tsx | 1 + docs/components/icons/Cli.tsx | 1 + docs/components/icons/ClientLogos.tsx | 1 + docs/components/icons/Close.tsx | 1 + docs/components/icons/Code.tsx | 1 + docs/components/icons/Content.tsx | 1 + docs/components/icons/Copy.tsx | 1 + docs/components/icons/Custom.tsx | 1 + docs/components/icons/DarkMode.tsx | 1 + docs/components/icons/Docs.tsx | 1 + docs/components/icons/Edit.tsx | 1 + docs/components/icons/Editor.tsx | 1 + docs/components/icons/Filter.tsx | 1 + docs/components/icons/FrontEndLogos.tsx | 1 + docs/components/icons/GitHub.tsx | 1 + docs/components/icons/GraphQl.tsx | 1 + docs/components/icons/Hamburger.tsx | 1 + docs/components/icons/Keystone.tsx | 1 + docs/components/icons/Lab.tsx | 1 + docs/components/icons/LightMode.tsx | 1 + docs/components/icons/Link.tsx | 1 + docs/components/icons/Migration.tsx | 1 + docs/components/icons/Nextjs.tsx | 1 + docs/components/icons/Organization.tsx | 1 + docs/components/icons/Postgres.tsx | 1 + docs/components/icons/Prisma.tsx | 1 + docs/components/icons/Profile.tsx | 1 + docs/components/icons/Quote.tsx | 1 + docs/components/icons/Relational.tsx | 1 + docs/components/icons/Relationship.tsx | 1 + docs/components/icons/Roadmap.tsx | 1 + docs/components/icons/Search.tsx | 1 + docs/components/icons/SearchKeys.tsx | 1 + docs/components/icons/Shield.tsx | 1 + docs/components/icons/Slack.tsx | 1 + docs/components/icons/Thinkmill.tsx | 1 + docs/components/icons/Tick.tsx | 1 + docs/components/icons/Twitter.tsx | 1 + docs/components/icons/Typescript.tsx | 1 + docs/components/icons/Updates.tsx | 1 + docs/components/icons/Watch.tsx | 1 + docs/components/icons/Welcome.tsx | 1 + docs/components/icons/WhyKeystone.tsx | 1 + docs/components/icons/util.tsx | 1 + docs/components/primitives/Alert.tsx | 1 + docs/components/primitives/Badge.tsx | 1 + docs/components/primitives/Button.tsx | 1 + docs/components/primitives/Code.tsx | 1 + docs/components/primitives/Emoji.tsx | 1 + docs/components/primitives/Field.tsx | 1 + docs/components/primitives/GitHubButton.tsx | 1 + docs/components/primitives/Gradient.tsx | 1 + docs/components/primitives/Highlight.tsx | 1 + docs/components/primitives/Loading.tsx | 1 + docs/components/primitives/SearchField.tsx | 1 + docs/components/primitives/Stack.tsx | 1 + docs/components/primitives/Status.tsx | 1 + docs/components/primitives/Type.tsx | 1 + docs/components/primitives/Well.tsx | 1 + docs/components/primitives/Wrapper.tsx | 1 + docs/next-env.d.ts | 1 - docs/package.json | 13 +- docs/pages/404.tsx | 6 +- docs/pages/_app.tsx | 1 + docs/pages/_document.tsx | 1 + docs/pages/docs/apis/access-control.mdx | 347 +-- docs/pages/docs/apis/auth.mdx | 8 +- docs/pages/docs/apis/config.mdx | 81 +- docs/pages/docs/apis/context.mdx | 4 +- docs/pages/docs/apis/fields.mdx | 124 +- docs/pages/docs/apis/filters.mdx | 2 + docs/pages/docs/apis/graphql.mdx | 6 +- docs/pages/docs/apis/hooks.mdx | 60 +- docs/pages/docs/apis/index.tsx | 1 + docs/pages/docs/apis/schema.mdx | 28 +- docs/pages/docs/apis/session.mdx | 6 +- docs/pages/docs/examples.tsx | 1 + docs/pages/docs/guides/cli.mdx | 2 +- .../docs/guides/custom-admin-ui-logo.mdx | 1 + .../guides/custom-admin-ui-navigation.mdx | 4 +- .../docs/guides/custom-admin-ui-pages.mdx | 3 +- docs/pages/docs/guides/custom-fields.mdx | 48 +- docs/pages/docs/guides/document-fields.mdx | 10 +- docs/pages/docs/guides/filters.mdx | 2 + docs/pages/docs/guides/hooks.mdx | 28 +- docs/pages/docs/guides/index.tsx | 1 + docs/pages/docs/guides/relationships.mdx | 20 +- docs/pages/docs/guides/testing.mdx | 10 +- docs/pages/docs/guides/virtual-fields.mdx | 65 +- docs/pages/docs/index.tsx | 3 +- .../embedded-mode-with-sqlite-nextjs.mdx | 26 +- docs/pages/docs/walkthroughs/index.tsx | 1 + docs/pages/ds.tsx | 1 + docs/pages/index.tsx | 6 +- docs/pages/updates/new-access-control.mdx | 181 ++ examples-staging/assets-cloud/CHANGELOG.md | 9 + examples-staging/assets-cloud/keystone.ts | 2 +- examples-staging/assets-cloud/package.json | 7 +- examples-staging/assets-cloud/schema.graphql | 87 +- examples-staging/assets-cloud/schema.prisma | 3 + examples-staging/assets-cloud/schema.ts | 6 +- examples-staging/assets-local/CHANGELOG.md | 9 + examples-staging/assets-local/keystone.ts | 2 +- examples-staging/assets-local/package.json | 7 +- examples-staging/assets-local/schema.graphql | 87 +- examples-staging/assets-local/schema.prisma | 3 + examples-staging/assets-local/schema.ts | 6 +- examples-staging/auth/CHANGELOG.md | 10 + examples-staging/auth/keystone.ts | 2 +- examples-staging/auth/package.json | 11 +- examples-staging/auth/schema.graphql | 29 +- examples-staging/auth/schema.prisma | 3 + examples-staging/auth/schema.ts | 15 +- examples-staging/basic/CHANGELOG.md | 15 + examples-staging/basic/admin/config.tsx | 2 +- .../basic/admin/fieldViews/Content.tsx | 3 +- .../basic/admin/fieldViews/Test.tsx | 7 +- .../basic/admin/pages/post/[id].tsx | 1 + examples-staging/basic/keystone.ts | 6 +- examples-staging/basic/package.json | 26 +- examples-staging/basic/schema.graphql | 84 +- examples-staging/basic/schema.prisma | 3 + examples-staging/basic/schema.ts | 18 +- examples-staging/ecommerce/CHANGELOG.md | 11 + examples-staging/ecommerce/keystone.ts | 2 +- .../ecommerce/mutations/addToCart.ts | 2 +- .../ecommerce/mutations/checkout.ts | 2 +- examples-staging/ecommerce/mutations/index.ts | 2 +- examples-staging/ecommerce/package.json | 17 +- examples-staging/ecommerce/schema.graphql | 181 +- examples-staging/ecommerce/schema.prisma | 3 + .../ecommerce/schemas/CartItem.ts | 20 +- examples-staging/ecommerce/schemas/Order.ts | 20 +- .../ecommerce/schemas/OrderItem.ts | 18 +- examples-staging/ecommerce/schemas/Product.ts | 16 +- .../ecommerce/schemas/ProductImage.ts | 14 +- examples-staging/ecommerce/schemas/Role.ts | 14 +- examples-staging/ecommerce/schemas/User.ts | 22 +- examples-staging/ecommerce/schemas/fields.ts | 2 +- examples-staging/ecommerce/seed-data/index.ts | 2 +- .../ecommerce/tests/mutations.test.ts | 4 +- examples-staging/ecommerce/types.ts | 2 +- examples-staging/embedded-nextjs/CHANGELOG.md | 9 + examples-staging/embedded-nextjs/keystone.ts | 2 +- examples-staging/embedded-nextjs/package.json | 9 +- .../embedded-nextjs/schema.graphql | 46 +- .../embedded-nextjs/schema.prisma | 3 + examples-staging/embedded-nextjs/schema.ts | 4 +- .../graphql-api-endpoint/CHANGELOG.md | 9 + .../graphql-api-endpoint/keystone.ts | 2 +- .../graphql-api-endpoint/package.json | 9 +- .../graphql-api-endpoint/schema.graphql | 73 +- .../graphql-api-endpoint/schema.prisma | 3 + .../graphql-api-endpoint/schema.ts | 6 +- examples-staging/playground/CHANGELOG.md | 11 + examples-staging/playground/keystone.ts | 31 +- examples-staging/playground/package.json | 7 +- examples-staging/playground/schema.graphql | 42 +- examples-staging/playground/schema.prisma | 3 + examples-staging/playground/schema.ts | 4 +- examples-staging/roles/CHANGELOG.md | 10 + examples-staging/roles/keystone.ts | 2 +- examples-staging/roles/package.json | 12 +- examples-staging/roles/schema.graphql | 127 +- examples-staging/roles/schema.prisma | 3 + examples-staging/roles/schema.ts | 40 +- examples-staging/sandbox/CHANGELOG.md | 8 + examples-staging/sandbox/keystone.ts | 2 +- examples-staging/sandbox/package.json | 7 +- examples-staging/sandbox/schema.graphql | 103 +- examples-staging/sandbox/schema.prisma | 3 + examples-staging/sandbox/schema.ts | 8 +- examples/README.md | 2 +- examples/blog/CHANGELOG.md | 11 + examples/blog/README.md | 28 +- examples/blog/keystone.ts | 8 +- examples/blog/package.json | 10 +- examples/blog/schema.graphql | 58 +- examples/blog/schema.prisma | 3 + examples/blog/schema.ts | 8 +- examples/blog/seed-data/data.ts | 77 + examples/blog/seed-data/index.ts | 67 + examples/custom-admin-ui-logo/CHANGELOG.md | 10 + .../admin/components/CustomLogo.tsx | 1 + .../custom-admin-ui-logo/admin/config.tsx | 2 +- examples/custom-admin-ui-logo/keystone.ts | 2 +- examples/custom-admin-ui-logo/package.json | 12 +- examples/custom-admin-ui-logo/schema.graphql | 20 +- examples/custom-admin-ui-logo/schema.prisma | 3 + examples/custom-admin-ui-logo/schema.ts | 10 +- .../custom-admin-ui-navigation/CHANGELOG.md | 9 + examples/custom-admin-ui-navigation/README.md | 2 +- .../admin/config.ts | 2 +- .../custom-admin-ui-navigation/keystone.ts | 2 +- .../custom-admin-ui-navigation/package.json | 8 +- .../custom-admin-ui-navigation/schema.graphql | 20 +- .../custom-admin-ui-navigation/schema.prisma | 3 + examples/custom-admin-ui-navigation/schema.ts | 10 +- examples/custom-admin-ui-pages/CHANGELOG.md | 10 + .../custom-admin-ui-pages/admin/config.ts | 2 +- .../admin/pages/custom-page.tsx | 1 + examples/custom-admin-ui-pages/keystone.ts | 2 +- examples/custom-admin-ui-pages/package.json | 10 +- examples/custom-admin-ui-pages/schema.graphql | 20 +- examples/custom-admin-ui-pages/schema.prisma | 3 + examples/custom-admin-ui-pages/schema.ts | 10 +- examples/custom-field-view/CHANGELOG.md | 13 + .../fields/related-links/components.tsx | 4 +- examples/custom-field-view/keystone.ts | 2 +- examples/custom-field-view/package.json | 16 +- examples/custom-field-view/schema.graphql | 20 +- examples/custom-field-view/schema.prisma | 3 + examples/custom-field-view/schema.ts | 10 +- examples/custom-field/CHANGELOG.md | 10 + examples/custom-field/keystone.ts | 2 +- examples/custom-field/package.json | 10 +- examples/custom-field/schema.graphql | 100 +- examples/custom-field/schema.prisma | 3 + examples/custom-field/schema.ts | 6 +- examples/custom-field/stars-field/index.ts | 37 +- examples/custom-field/stars-field/views.tsx | 2 +- examples/default-values/CHANGELOG.md | 9 + examples/default-values/keystone.ts | 2 +- examples/default-values/package.json | 7 +- examples/default-values/schema.graphql | 20 +- examples/default-values/schema.prisma | 3 + examples/default-values/schema.ts | 10 +- examples/document-field/CHANGELOG.md | 10 + examples/document-field/keystone.ts | 2 +- examples/document-field/package.json | 11 +- examples/document-field/schema.graphql | 88 +- examples/document-field/schema.prisma | 3 + examples/document-field/schema.ts | 8 +- examples/extend-graphql-schema/CHANGELOG.md | 9 + .../extend-graphql-schema/custom-schema.ts | 2 +- examples/extend-graphql-schema/keystone.ts | 2 +- examples/extend-graphql-schema/package.json | 7 +- examples/extend-graphql-schema/schema.graphql | 87 +- examples/extend-graphql-schema/schema.prisma | 3 + examples/extend-graphql-schema/schema.ts | 6 +- examples/json/CHANGELOG.md | 9 + examples/json/keystone.ts | 2 +- examples/json/package.json | 7 +- examples/json/schema.graphql | 67 +- examples/json/schema.prisma | 3 + examples/json/schema.ts | 4 +- examples/task-manager/CHANGELOG.md | 11 + examples/task-manager/README.md | 30 +- examples/task-manager/keystone.ts | 8 +- examples/task-manager/package.json | 10 +- examples/task-manager/schema.graphql | 20 +- examples/task-manager/schema.prisma | 3 + examples/task-manager/schema.ts | 10 +- examples/task-manager/seed-data/data.ts | 72 + examples/task-manager/seed-data/index.ts | 66 + examples/testing/CHANGELOG.md | 10 + examples/testing/README.md | 8 +- examples/testing/babel.config.js | 6 - examples/testing/example.test.ts | 4 +- examples/testing/keystone.ts | 2 +- examples/testing/package.json | 15 +- examples/testing/schema.graphql | 22 +- examples/testing/schema.prisma | 3 + examples/testing/schema.ts | 26 +- examples/virtual-field/CHANGELOG.md | 9 + examples/virtual-field/README.md | 32 +- examples/virtual-field/keystone.ts | 2 +- examples/virtual-field/package.json | 8 +- examples/virtual-field/schema.graphql | 87 +- examples/virtual-field/schema.prisma | 3 + examples/virtual-field/schema.ts | 34 +- examples/with-auth/CHANGELOG.md | 10 + examples/with-auth/README.md | 2 +- examples/with-auth/keystone.ts | 2 +- examples/with-auth/package.json | 9 +- examples/with-auth/schema.graphql | 22 +- examples/with-auth/schema.prisma | 3 + examples/with-auth/schema.ts | 14 +- package.json | 25 +- packages/admin-ui-utils/CHANGELOG.md | 6 + packages/admin-ui-utils/package.json | 17 +- packages/admin-ui-utils/src/index.ts | 11 +- packages/auth/CHANGELOG.md | 25 + packages/auth/package.json | 21 +- packages/auth/src/components/Icons.tsx | 3 +- .../auth/src/components/SigninContainer.tsx | 3 +- packages/auth/src/gql/getBaseAuthSchema.ts | 2 +- .../auth/src/gql/getInitFirstItemSchema.ts | 2 +- .../auth/src/gql/getMagicAuthLinkSchema.ts | 2 +- .../auth/src/gql/getPasswordResetSchema.ts | 2 +- packages/auth/src/index.ts | 4 +- packages/auth/src/lib/createAuthToken.ts | 2 +- packages/auth/src/lib/findMatchingIdentity.ts | 4 +- packages/auth/src/lib/getErrorMessage.ts | 2 +- packages/auth/src/lib/validateAuthToken.ts | 2 +- packages/auth/src/lib/validateSecret.ts | 2 +- packages/auth/src/pages/InitPage.tsx | 7 +- packages/auth/src/pages/SigninPage.tsx | 3 +- packages/auth/src/schema.ts | 5 +- packages/auth/src/templates/init.ts | 2 +- packages/auth/src/types.ts | 2 +- packages/cloudinary/CHANGELOG.md | 27 + packages/cloudinary/package.json | 18 +- packages/cloudinary/src/index.ts | 105 +- packages/cloudinary/src/test-fixtures.skip.ts | 4 +- packages/cloudinary/src/views/Field.tsx | 3 +- packages/cloudinary/src/views/index.tsx | 5 +- packages/fields-document/CHANGELOG.md | 31 + packages/fields-document/package.json | 27 +- .../src/DocumentEditor/Toolbar.tsx | 1 + .../src/DocumentEditor/alignment.tsx | 1 + .../src/DocumentEditor/blockquote.test.tsx | 1 + .../src/DocumentEditor/blockquote.tsx | 1 + .../src/DocumentEditor/code-block.test.tsx | 1 + .../src/DocumentEditor/code-block.tsx | 1 + .../DocumentEditor/component-blocks/api.tsx | 1 + .../document-features-normalization.test.tsx | 1 + .../DocumentEditor/component-blocks/form.tsx | 2 +- .../DocumentEditor/component-blocks/index.tsx | 1 + .../insert-break-and-delete.test.tsx | 1 + .../insertion-and-preview-props.test.tsx | 1 + .../component-blocks/normalization.test.tsx | 1 + .../src/DocumentEditor/divider.test.tsx | 1 + .../src/DocumentEditor/heading.test.tsx | 1 + .../src/DocumentEditor/heading.tsx | 1 + .../src/DocumentEditor/index.tsx | 1 + .../src/DocumentEditor/insert-menu.test.tsx | 1 + .../src/DocumentEditor/insert-menu.tsx | 1 + .../src/DocumentEditor/layouts.test.tsx | 1 + .../src/DocumentEditor/layouts.tsx | 1 + .../src/DocumentEditor/leaf.tsx | 1 + .../src/DocumentEditor/link.tsx | 1 + .../src/DocumentEditor/lists.test.tsx | 1 + .../src/DocumentEditor/lists.tsx | 1 + .../markdown-link-shortcut.test.tsx | 1 + .../src/DocumentEditor/marks.test.tsx | 1 + .../pasting/html-from-other-editors.test.tsx | 1 + .../DocumentEditor/pasting/markdown.test.tsx | 1 + .../primitives/inline-dialog.tsx | 1 + .../src/DocumentEditor/primitives/toolbar.tsx | 1 + .../src/DocumentEditor/relationship.tsx | 3 +- .../src/DocumentEditor/render-element.tsx | 1 + .../src/DocumentEditor/shortcuts.test.tsx | 1 + .../src/DocumentEditor/soft-breaks.test.tsx | 1 + .../DocumentEditor/tests/test-utils.test.tsx | 1 + packages/fields-document/src/index.ts | 29 +- .../fields-document/src/relationship-data.tsx | 26 +- .../src/tests/test-fixtures.ts | 3 +- .../fields-document/src/validation.test.tsx | 1 + packages/fields-document/src/views.tsx | 5 +- packages/fields/CHANGELOG.md | 6 + packages/fields/README.md | 2 + packages/fields/package.json | 46 +- packages/fields/src/get-index-type.ts | 12 - packages/fields/src/index.ts | 19 +- packages/fields/src/resolve-view.ts | 5 - packages/fields/src/types/file/README.md | 37 - .../fields/types/checkbox/views/package.json | 4 - .../fields/types/decimal/views/package.json | 4 - packages/fields/types/file/views/package.json | 4 - .../fields/types/float/views/package.json | 4 - .../fields/types/image/views/package.json | 4 - .../fields/types/integer/views/package.json | 4 - packages/fields/types/json/views/package.json | 4 - .../fields/types/password/views/package.json | 4 - .../views/RelationshipSelect/package.json | 4 - .../types/relationship/views/package.json | 4 - .../fields/types/select/views/package.json | 4 - packages/fields/types/text/views/package.json | 4 - .../fields/types/timestamp/views/package.json | 4 - .../fields/types/virtual/views/package.json | 4 - packages/keystone/CHANGELOG.md | 105 + packages/keystone/admin-ui/utils/package.json | 4 + packages/keystone/fields/package.json | 4 + .../fields/types/checkbox/views/package.json | 4 + .../fields/types/decimal/views/package.json | 4 + .../fields/types/file/utils/package.json | 4 + .../fields/types/file/views/package.json | 4 + .../fields/types/float/views/package.json | 4 + .../fields/types/image/utils/package.json | 4 + .../fields/types/image/views/package.json | 4 + .../fields/types/integer/views/package.json | 4 + .../fields/types/json/views/package.json | 4 + .../fields/types/password/views/package.json | 4 + .../views/RelationshipSelect/package.json | 4 + .../types/relationship/views/package.json | 4 + .../fields/types/select/views/package.json | 4 + .../fields/types/text/views/package.json | 4 + .../fields/types/timestamp/views/package.json | 4 + .../fields/types/virtual/views/package.json | 4 + packages/keystone/package.json | 87 +- .../admin-ui/id-field-view.tsx | 45 +- .../admin-ui/next-config.ts | 7 +- .../admin-ui/pages/App/index.tsx | 3 +- .../admin-ui/pages/HomePage/index.tsx | 20 +- .../admin-ui/pages/ItemPage/index.tsx | 55 +- .../pages/ListPage/FieldSelection.tsx | 21 +- .../admin-ui/pages/ListPage/FilterAdd.tsx | 32 +- .../admin-ui/pages/ListPage/FilterList.tsx | 18 +- .../admin-ui/pages/ListPage/SortSelection.tsx | 33 +- .../admin-ui/pages/ListPage/index.tsx | 55 +- .../admin-ui/pages/ListPage/useFilters.tsx | 12 +- .../pages/ListPage/useSelectedFields.tsx | 2 +- .../admin-ui/pages/ListPage/useSort.tsx | 7 +- .../admin-ui/pages/NoAccessPage/index.tsx | 3 +- .../next-graphql.ts | 4 +- .../node-api.ts | 2 +- .../src/admin-ui/admin-meta-graphql.ts | 5 +- .../src/admin-ui/components/CellContainer.tsx | 3 +- .../src/admin-ui/components/CellLink.tsx | 3 +- .../src/admin-ui/components/Container.tsx | 3 +- .../admin-ui/components/CreateItemDrawer.tsx | 67 +- .../src/admin-ui/components/Errors.tsx | 3 +- .../keystone/src/admin-ui/components/Logo.tsx | 3 +- .../src/admin-ui/components/Navigation.tsx | 29 +- .../src/admin-ui/components/PageContainer.tsx | 4 +- .../src/admin-ui/components/Pagination.tsx | 1 + .../src/admin-ui/components/SignoutButton.tsx | 3 +- .../components/__tests__/Pagination.test.tsx | 5 + .../keystone/src/admin-ui/components/index.ts | 2 +- packages/keystone/src/admin-ui/context.tsx | 13 +- .../src/admin-ui/system/createAdminMeta.ts | 11 +- .../admin-ui/system/createAdminUIServer.ts | 49 - .../src/admin-ui/system/generateAdminUI.ts | 5 +- .../src/admin-ui/system/getAdminMetaSchema.ts | 182 +- .../keystone/src/admin-ui/system/index.ts | 1 - .../keystone/src/admin-ui/templates/api.ts | 4 +- .../keystone/src/admin-ui/templates/app.ts | 8 +- .../keystone/src/admin-ui/templates/index.ts | 79 +- .../src/admin-ui/templates/no-access.ts | 2 +- .../src/admin-ui/utils}/Fields.tsx | 3 +- .../src/admin-ui/utils}/dataGetter.ts | 2 +- ...getRootGraphQLFieldsFromFieldController.ts | 2 +- packages/keystone/src/admin-ui/utils/index.ts | 6 + .../src/admin-ui/utils}/item-form.ts | 12 +- .../src/admin-ui/utils}/serialization.tsx | 2 +- .../src/admin-ui/utils/useAdminMeta.tsx | 25 +- .../src/admin-ui/utils}/useInvalidFields.ts | 2 +- .../src/admin-ui/utils/useLazyMetadata.tsx | 54 +- packages/keystone/src/artifacts.ts | 13 +- packages/keystone/src/fields/index.ts | 14 + packages/keystone/src/fields/resolve-view.ts | 5 + .../src/fields}/tests/test-fixtures.ts | 9 +- .../src/fields}/types/autoIncrement/index.ts | 31 +- .../autoIncrement/tests/test-fixtures.ts | 8 +- .../src/fields}/types/checkbox/index.ts | 20 +- .../types/checkbox/tests/test-fixtures.ts | 5 +- .../fields}/types/checkbox/views/index.tsx | 11 +- .../src/fields}/types/decimal/index.ts | 28 +- .../types/decimal/tests/test-fixtures.ts | 8 +- .../src/fields}/types/decimal/views/index.tsx | 8 +- .../src/fields}/types/file/index.ts | 43 +- .../fields}/types/file/test-files/graphql.jpg | Bin .../types/file/test-files/keystone.jpeg | Bin .../types/file/test-files/keystone.jpg | Bin .../types/file/test-files/keystone.txt | Bin .../fields}/types/file/test-files/react.jpg | Bin .../types/file/test-files/thinkmill.jpg | Bin .../types/file/test-files/thinkmill1.jpg | Bin .../types/file/test-files/thinkmill2.jpg | Bin .../fields}/types/file/tests/test-fixtures.ts | 5 +- .../keystone/src/fields/types/file/utils.ts | 16 + .../src/fields}/types/file/views/Field.tsx | 5 +- .../src/fields}/types/file/views/index.tsx | 7 +- .../src/fields}/types/float/index.ts | 21 +- .../types/float/tests/test-fixtures.ts | 3 +- .../src/fields}/types/float/views/index.tsx | 8 +- .../src/fields}/types/image/index.ts | 53 +- .../types/image/test-files/badfile.txt | 0 .../types/image/test-files/graphql.jpg | Bin .../fields}/types/image/test-files/keystone | Bin .../types/image/test-files/keystone.jpeg | Bin .../types/image/test-files/keystone.jpg | Bin .../fields}/types/image/test-files/react.jpg | Bin .../types/image/test-files/thinkmill.jpg | Bin .../types/image/test-files/thinkmill1.jpg | Bin .../types/image/test-files/thinkmill2.jpg | Bin .../types/image/tests/test-fixtures.ts | 7 +- .../keystone/src/fields/types/image/utils.ts | 23 + .../src/fields}/types/image/views/Field.tsx | 5 +- .../src/fields}/types/image/views/index.tsx | 7 +- .../src/fields}/types/integer/index.ts | 24 +- .../types/integer/tests/test-fixtures.ts | 3 +- .../src/fields}/types/integer/views/index.tsx | 8 +- .../src/fields}/types/json/index.ts | 14 +- .../fields}/types/json/tests/test-fixtures.ts | 3 +- .../src/fields}/types/json/views/index.tsx | 11 +- .../src/fields}/types/password/index.ts | 30 +- .../types/password/tests/test-fixtures.ts | 2 - .../fields}/types/password/views/index.tsx | 17 +- .../src/fields}/types/relationship/index.ts | 45 +- .../relationship/tests/implementation.test.ts | 4 +- .../relationship/views/RelationshipSelect.tsx | 5 +- .../relationship/views/cards/InlineCreate.tsx | 15 +- .../relationship/views/cards/InlineEdit.tsx | 38 +- .../types/relationship/views/cards/index.tsx | 11 +- .../relationship/views/cards/useItemState.tsx | 6 +- .../types/relationship/views/index.tsx | 25 +- .../src/fields}/types/select/index.ts | 49 +- .../types/select/tests/test-fixtures.ts | 4 +- .../src/fields}/types/select/views/index.tsx | 13 +- .../src/fields}/types/text/index.ts | 24 +- .../fields}/types/text/tests/test-fixtures.ts | 6 +- .../src/fields}/types/text/views/index.tsx | 11 +- .../src/fields}/types/timestamp/index.ts | 23 +- .../types/timestamp/tests/test-fixtures.ts | 7 +- .../types/timestamp/views/__tests__/index.tsx | 0 .../types/timestamp/views/__tests__/utils.tsx | 0 .../fields}/types/timestamp/views/index.tsx | 13 +- .../fields}/types/timestamp/views/utils.ts | 0 .../src/fields}/types/virtual/index.ts | 10 +- .../types/virtual/views/PrettyData.tsx | 0 .../src/fields}/types/virtual/views/index.tsx | 9 +- packages/keystone/src/index.ts | 6 +- .../src/lib/config/applyIdFieldDefaults.ts | 2 +- .../keystone/src/lib/config/initConfig.ts | 2 +- .../keystone/src/lib/context/createContext.ts | 9 +- .../src/lib/context/createFilesContext.ts | 12 +- .../src/lib/context/createImagesContext.ts | 12 +- .../context/executeGraphQLFieldToRootVal.ts | 2 +- .../executeGraphQLFieldWithSelection.ts | 2 +- packages/keystone/src/lib/context/itemAPI.ts | 2 +- .../keystone/src/lib/core/access-control.ts | 187 +- .../keystone/src/lib/core/field-assertions.ts | 10 +- .../keystone/src/lib/core/graphql-schema.ts | 30 +- .../src/lib/core/mutations/access-control.ts | 198 +- .../src/lib/core/mutations/create-update.ts | 108 +- .../keystone/src/lib/core/mutations/delete.ts | 38 +- .../keystone/src/lib/core/mutations/hooks.ts | 14 +- .../keystone/src/lib/core/mutations/index.ts | 62 +- .../nested-mutation-many-input-resolvers.ts | 15 +- .../nested-mutation-one-input-resolvers.ts | 15 +- .../src/lib/core/mutations/validation.ts | 12 +- .../keystone/src/lib/core/prisma-schema.ts | 7 +- .../keystone/src/lib/core/queries/index.ts | 18 +- .../src/lib/core/queries/output-field.ts | 44 +- .../src/lib/core/queries/resolvers.ts | 80 +- .../src/lib/core/resolve-relationships.ts | 2 +- .../keystone/src/lib/core/types-for-lists.ts | 301 ++- packages/keystone/src/lib/core/utils.ts | 2 +- .../keystone/src/lib/core/where-inputs.ts | 2 +- .../keystone/src/lib/createGraphQLSchema.ts | 2 +- packages/keystone/src/lib/createSystem.ts | 15 +- packages/keystone/src/lib/id-field.ts | 49 +- .../keystone/src/lib/keystone-cloud/assets.ts | 2 +- .../keystone/src/lib/schema-type-printer.tsx | 12 +- .../keystone/src/lib/server/addHealthCheck.ts | 2 +- .../src/lib/server/createAdminUIMiddleware.ts | 72 + .../src/lib/server/createApolloServer.ts | 37 +- .../src/lib/server/createExpressServer.ts | 43 +- packages/keystone/src/next.ts | 2 +- packages/keystone/src/package-path.ts | 8 + packages/keystone/src/schema/index.ts | 18 +- packages/keystone/src/schema/schema.ts | 2 +- packages/keystone/src/scripts/build/build.ts | 2 +- packages/keystone/src/scripts/run/dev.ts | 63 +- packages/keystone/src/scripts/run/start.ts | 22 +- .../__snapshots__/artifacts.test.ts.snap | 46 +- .../src/scripts/tests/artifacts.test.ts | 6 +- .../keystone/src/scripts/tests/build.test.ts | 35 +- .../fixtures/basic-project/schema.graphql | 42 +- .../fixtures/basic-project/schema.prisma | 3 + .../src/scripts/tests/migrations.test.ts | 95 +- packages/keystone/src/scripts/tests/utils.tsx | 8 +- packages/keystone/src/session/index.ts | 10 +- packages/keystone/src/system.ts | 5 + packages/keystone/src/testing.ts | 91 + .../src => keystone/src/types}/admin-meta.ts | 2 + .../{types/src => keystone/src/types}/base.ts | 0 .../src/types/config/access-control.ts | 141 ++ .../src/types}/config/fields.ts | 18 +- .../src/types}/config/hooks.ts | 2 +- .../src/types}/config/index.ts | 29 +- .../src/types}/config/lists.ts | 18 +- .../src => keystone/src/types}/context.ts | 7 + .../{types/src => keystone/src/types}/core.ts | 0 .../keystone/src/types/filters/enum-filter.ts | 76 + .../src/types}/filters/index.ts | 0 .../src/types/filters/providers/postgresql.ts | 647 +++++ .../src/types/filters/providers/sqlite.ts | 438 ++++ packages/keystone/src/types/index.ts | 11 + .../json-field-type-polyfill-for-sqlite.ts | 24 +- .../src => keystone/src/types}/next-fields.ts | 179 +- .../src/types}/schema/graphql-ts-schema.ts | 6 +- packages/keystone/src/types/schema/index.ts | 1 + .../types/schema/schema-api-with-context.d.ts | 6 + .../types}/schema/schema-api-with-context.js | 0 .../src => keystone/src/types}/session.ts | 0 .../src => keystone/src/types}/utils.ts | 0 packages/keystone/static/admin-error.html | 52 + packages/keystone/system/package.json | 4 + packages/keystone/testing/package.json | 4 + packages/keystone/types/package.json | 4 + packages/session-store-redis/CHANGELOG.md | 11 + packages/session-store-redis/package.json | 6 +- packages/session-store-redis/src/index.ts | 2 +- packages/testing/CHANGELOG.md | 6 + packages/testing/README.md | 2 +- packages/testing/package.json | 9 +- packages/testing/src/index.ts | 92 +- packages/types/CHANGELOG.md | 6 + packages/types/README.md | 2 + packages/types/package.json | 13 +- packages/types/src/config/access-control.ts | 108 - packages/types/src/filters/enum-filter.ts | 76 - .../types/src/filters/providers/postgresql.ts | 647 ----- .../types/src/filters/providers/sqlite.ts | 438 ---- packages/types/src/index.ts | 16 +- packages/types/src/schema/index.ts | 1 - .../src/schema/schema-api-with-context.d.ts | 6 - packages/utils/CHANGELOG.md | 6 + packages/utils/package.json | 6 +- packages/utils/src/index.ts | 44 +- prisma-utils/CHANGELOG.md | 8 + prisma-utils/package.json | 6 +- prisma-utils/src/index.ts | 32 +- tests/admin-ui-tests/init.test.ts | 10 + tests/admin-ui-tests/list-view-crud.test.ts | 106 + tests/admin-ui-tests/navigation.test.ts | 75 + tests/admin-ui-tests/package.json | 7 +- tests/admin-ui-tests/utils.ts | 47 +- tests/api-tests/CHANGELOG.md | 10 + .../access-control/authed-user.test.ts | 72 + tests/api-tests/access-control/authed.test.ts | 485 ---- .../access-control/field-access.test.ts | 131 + .../access-control/list-access.test.ts | 515 ++++ ...static.test.ts => mutations-field.test.ts} | 15 +- ....test.ts => mutations-list-filter.test.ts} | 21 +- ...ic.test.ts => mutations-list-item.test.ts} | 35 +- .../access-control/not-authed.test.ts | 390 --- .../api-tests/access-control/schema-utils.ts | 126 + tests/api-tests/access-control/schema.test.ts | 472 +++- tests/api-tests/access-control/utils.ts | 157 +- tests/api-tests/auth-header.test.ts | 32 +- .../api-tests/default-value/defaults.test.ts | 8 +- tests/api-tests/extend-express-app.test.ts | 32 + .../extend-graphql-schema.test.ts | 6 +- tests/api-tests/fields/crud.test.ts | 17 +- tests/api-tests/fields/filter.test.ts | 15 +- tests/api-tests/fields/required.test.ts | 6 +- tests/api-tests/fields/types/Virtual.test.ts | 54 +- tests/api-tests/fields/types/document.test.ts | 12 +- tests/api-tests/fields/unique.test.ts | 20 +- tests/api-tests/fields/unsupported.test.ts | 11 +- tests/api-tests/healthcheck.test.ts | 6 +- tests/api-tests/hooks/auth-hooks.test.skip.ts | 6 +- tests/api-tests/hooks/hook-errors.test.ts | 14 +- tests/api-tests/hooks/list-hooks.test.ts | 6 +- tests/api-tests/hooks/validation.test.ts | 8 +- tests/api-tests/id-field.test.ts | 6 +- tests/api-tests/new-interfaces.test.ts | 6 +- tests/api-tests/package.json | 10 +- tests/api-tests/queries/cache-hints.test.ts | 12 +- tests/api-tests/queries/filters.test.ts | 20 +- tests/api-tests/queries/limits.test.ts | 28 +- tests/api-tests/queries/orderBy.test.ts | 12 +- tests/api-tests/queries/relationships.test.ts | 14 +- .../many-to-many-one-sided.test.ts | 12 +- .../crud-self-ref/many-to-many.test.ts | 12 +- .../one-to-many-one-sided.test.ts | 12 +- .../crud-self-ref/one-to-many.test.ts | 18 +- .../crud-self-ref/one-to-one.test.ts | 14 +- .../crud/many-to-many-one-sided.test.ts | 15 +- .../relationships/crud/many-to-many.test.ts | 12 +- .../crud/one-to-many-one-sided.test.ts | 14 +- .../relationships/crud/one-to-many.test.ts | 16 +- .../relationships/crud/one-to-one.test.ts | 16 +- .../filtering/access-control.test.ts | 14 +- .../relationships/filtering/filtering.test.ts | 14 +- .../relationships/filtering/nested.test.ts | 12 +- .../relationships/many-to-one-to-one.test.ts | 24 +- .../nested-mutations/connect-many.test.ts | 10 +- .../nested-mutations/connect-singular.test.ts | 24 +- .../create-and-connect-many.test.ts | 14 +- .../create-and-connect-singular.test.ts | 6 +- .../nested-mutations/create-many.test.ts | 26 +- .../nested-mutations/create-singular.test.ts | 34 +- .../nested-mutations/disconnect-many.test.ts | 10 +- .../disconnect-singular.test.ts | 8 +- .../reconnect-many-to-one.test.ts | 8 +- .../nested-mutations/set-many.test.ts | 12 +- .../two-way-backreference/to-many.test.ts | 8 +- .../to-one-required.test.ts | 6 +- .../relationships/shared-names.test.ts | 16 +- tests/api-tests/utils.ts | 14 +- tests/benchmarks/CHANGELOG.md | 7 + tests/benchmarks/fixtures/create-related.js | 6 +- tests/benchmarks/fixtures/create.js | 6 +- tests/benchmarks/fixtures/query.js | 6 +- tests/benchmarks/package.json | 6 +- tests/examples-smoke-tests/package.json | 2 +- tests/examples-smoke-tests/utils.ts | 2 +- tests/test-projects/basic/CHANGELOG.md | 9 + tests/test-projects/basic/keystone.ts | 2 +- tests/test-projects/basic/package.json | 7 +- tests/test-projects/basic/schema.graphql | 73 +- tests/test-projects/basic/schema.prisma | 9 + tests/test-projects/basic/schema.ts | 19 +- .../crud-notifications/CHANGELOG.md | 9 + .../crud-notifications/keystone.ts | 15 +- .../crud-notifications/package.json | 7 +- .../crud-notifications/schema.graphql | 20 +- .../crud-notifications/schema.prisma | 3 + .../crud-notifications/schema.ts | 22 +- yarn.lock | 2246 ++++++++--------- 836 files changed, 9844 insertions(+), 8514 deletions(-) delete mode 100644 .changeset/brave-paws-sneeze.md create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 docs/pages/updates/new-access-control.mdx create mode 100644 examples/blog/seed-data/data.ts create mode 100644 examples/blog/seed-data/index.ts create mode 100644 examples/task-manager/seed-data/data.ts create mode 100644 examples/task-manager/seed-data/index.ts delete mode 100644 packages/fields/src/get-index-type.ts delete mode 100644 packages/fields/src/resolve-view.ts delete mode 100644 packages/fields/src/types/file/README.md delete mode 100644 packages/fields/types/checkbox/views/package.json delete mode 100644 packages/fields/types/decimal/views/package.json delete mode 100644 packages/fields/types/file/views/package.json delete mode 100644 packages/fields/types/float/views/package.json delete mode 100644 packages/fields/types/image/views/package.json delete mode 100644 packages/fields/types/integer/views/package.json delete mode 100644 packages/fields/types/json/views/package.json delete mode 100644 packages/fields/types/password/views/package.json delete mode 100644 packages/fields/types/relationship/views/RelationshipSelect/package.json delete mode 100644 packages/fields/types/relationship/views/package.json delete mode 100644 packages/fields/types/select/views/package.json delete mode 100644 packages/fields/types/text/views/package.json delete mode 100644 packages/fields/types/timestamp/views/package.json delete mode 100644 packages/fields/types/virtual/views/package.json create mode 100644 packages/keystone/admin-ui/utils/package.json create mode 100644 packages/keystone/fields/package.json create mode 100644 packages/keystone/fields/types/checkbox/views/package.json create mode 100644 packages/keystone/fields/types/decimal/views/package.json create mode 100644 packages/keystone/fields/types/file/utils/package.json create mode 100644 packages/keystone/fields/types/file/views/package.json create mode 100644 packages/keystone/fields/types/float/views/package.json create mode 100644 packages/keystone/fields/types/image/utils/package.json create mode 100644 packages/keystone/fields/types/image/views/package.json create mode 100644 packages/keystone/fields/types/integer/views/package.json create mode 100644 packages/keystone/fields/types/json/views/package.json create mode 100644 packages/keystone/fields/types/password/views/package.json create mode 100644 packages/keystone/fields/types/relationship/views/RelationshipSelect/package.json create mode 100644 packages/keystone/fields/types/relationship/views/package.json create mode 100644 packages/keystone/fields/types/select/views/package.json create mode 100644 packages/keystone/fields/types/text/views/package.json create mode 100644 packages/keystone/fields/types/timestamp/views/package.json create mode 100644 packages/keystone/fields/types/virtual/views/package.json delete mode 100644 packages/keystone/src/admin-ui/system/createAdminUIServer.ts rename packages/{admin-ui-utils/src => keystone/src/admin-ui/utils}/Fields.tsx (97%) rename packages/{admin-ui-utils/src => keystone/src/admin-ui/utils}/dataGetter.ts (97%) rename packages/{admin-ui-utils/src => keystone/src/admin-ui/utils}/getRootGraphQLFieldsFromFieldController.ts (95%) create mode 100644 packages/keystone/src/admin-ui/utils/index.ts rename packages/{admin-ui-utils/src => keystone/src/admin-ui/utils}/item-form.ts (87%) rename packages/{admin-ui-utils/src => keystone/src/admin-ui/utils}/serialization.tsx (96%) rename packages/{admin-ui-utils/src => keystone/src/admin-ui/utils}/useInvalidFields.ts (93%) create mode 100644 packages/keystone/src/fields/index.ts create mode 100644 packages/keystone/src/fields/resolve-view.ts rename packages/{fields/src => keystone/src/fields}/tests/test-fixtures.ts (96%) rename packages/{fields/src => keystone/src/fields}/types/autoIncrement/index.ts (61%) rename packages/{fields/src => keystone/src/fields}/types/autoIncrement/tests/test-fixtures.ts (94%) rename packages/{fields/src => keystone/src/fields}/types/checkbox/index.ts (64%) rename packages/{fields/src => keystone/src/fields}/types/checkbox/tests/test-fixtures.ts (89%) rename packages/{fields/src => keystone/src/fields}/types/checkbox/views/index.tsx (94%) rename packages/{fields/src => keystone/src/fields}/types/decimal/index.ts (81%) rename packages/{fields/src => keystone/src/fields}/types/decimal/tests/test-fixtures.ts (86%) rename packages/{fields/src => keystone/src/fields}/types/decimal/views/index.tsx (95%) rename packages/{fields/src => keystone/src/fields}/types/file/index.ts (74%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/graphql.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/keystone.jpeg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/keystone.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/keystone.txt (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/react.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/thinkmill.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/thinkmill1.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/test-files/thinkmill2.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/file/tests/test-fixtures.ts (97%) create mode 100644 packages/keystone/src/fields/types/file/utils.ts rename packages/{fields/src => keystone/src/fields}/types/file/views/Field.tsx (98%) rename packages/{fields/src => keystone/src/fields}/types/file/views/index.tsx (97%) rename packages/{fields/src => keystone/src/fields}/types/float/index.ts (63%) rename packages/{fields/src => keystone/src/fields}/types/float/tests/test-fixtures.ts (89%) rename packages/{fields/src => keystone/src/fields}/types/float/views/index.tsx (95%) rename packages/{fields/src => keystone/src/fields}/types/image/index.ts (72%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/badfile.txt (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/graphql.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/keystone (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/keystone.jpeg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/keystone.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/react.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/thinkmill.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/thinkmill1.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/test-files/thinkmill2.jpg (100%) rename packages/{fields/src => keystone/src/fields}/types/image/tests/test-fixtures.ts (96%) create mode 100644 packages/keystone/src/fields/types/image/utils.ts rename packages/{fields/src => keystone/src/fields}/types/image/views/Field.tsx (98%) rename packages/{fields/src => keystone/src/fields}/types/image/views/index.tsx (97%) rename packages/{fields/src => keystone/src/fields}/types/integer/index.ts (60%) rename packages/{fields/src => keystone/src/fields}/types/integer/tests/test-fixtures.ts (90%) rename packages/{fields/src => keystone/src/fields}/types/integer/views/index.tsx (96%) rename packages/{fields/src => keystone/src/fields}/types/json/index.ts (70%) rename packages/{fields/src => keystone/src/fields}/types/json/tests/test-fixtures.ts (89%) rename packages/{fields/src => keystone/src/fields}/types/json/views/index.tsx (93%) rename packages/{fields/src => keystone/src/fields}/types/password/index.ts (84%) rename packages/{fields/src => keystone/src/fields}/types/password/tests/test-fixtures.ts (97%) rename packages/{fields/src => keystone/src/fields}/types/password/views/index.tsx (98%) rename packages/{fields/src => keystone/src/fields}/types/relationship/index.ts (87%) rename packages/{fields/src => keystone/src/fields}/types/relationship/tests/implementation.test.ts (97%) rename packages/{fields/src => keystone/src/fields}/types/relationship/views/RelationshipSelect.tsx (98%) rename packages/{fields/src => keystone/src/fields}/types/relationship/views/cards/InlineCreate.tsx (91%) rename packages/{fields/src => keystone/src/fields}/types/relationship/views/cards/InlineEdit.tsx (89%) rename packages/{fields/src => keystone/src/fields}/types/relationship/views/cards/index.tsx (98%) rename packages/{fields/src => keystone/src/fields}/types/relationship/views/cards/useItemState.tsx (95%) rename packages/{fields/src => keystone/src/fields}/types/relationship/views/index.tsx (97%) rename packages/{fields/src => keystone/src/fields}/types/select/index.ts (68%) rename packages/{fields/src => keystone/src/fields}/types/select/tests/test-fixtures.ts (98%) rename packages/{fields/src => keystone/src/fields}/types/select/views/index.tsx (96%) rename packages/{fields/src => keystone/src/fields}/types/text/index.ts (65%) rename packages/{fields/src => keystone/src/fields}/types/text/tests/test-fixtures.ts (89%) rename packages/{fields/src => keystone/src/fields}/types/text/views/index.tsx (96%) rename packages/{fields/src => keystone/src/fields}/types/timestamp/index.ts (68%) rename packages/{fields/src => keystone/src/fields}/types/timestamp/tests/test-fixtures.ts (95%) rename packages/{fields/src => keystone/src/fields}/types/timestamp/views/__tests__/index.tsx (100%) rename packages/{fields/src => keystone/src/fields}/types/timestamp/views/__tests__/utils.tsx (100%) rename packages/{fields/src => keystone/src/fields}/types/timestamp/views/index.tsx (97%) rename packages/{fields/src => keystone/src/fields}/types/timestamp/views/utils.ts (100%) rename packages/{fields/src => keystone/src/fields}/types/virtual/index.ts (82%) rename packages/{fields/src => keystone/src/fields}/types/virtual/views/PrettyData.tsx (100%) rename packages/{fields/src => keystone/src/fields}/types/virtual/views/index.tsx (94%) create mode 100644 packages/keystone/src/lib/server/createAdminUIMiddleware.ts create mode 100644 packages/keystone/src/package-path.ts create mode 100644 packages/keystone/src/system.ts create mode 100644 packages/keystone/src/testing.ts rename packages/{types/src => keystone/src/types}/admin-meta.ts (99%) rename packages/{types/src => keystone/src/types}/base.ts (100%) create mode 100644 packages/keystone/src/types/config/access-control.ts rename packages/{types/src => keystone/src/types}/config/fields.ts (54%) rename packages/{types/src => keystone/src/types}/config/hooks.ts (98%) rename packages/{types/src => keystone/src/types}/config/index.ts (91%) rename packages/{types/src => keystone/src/types}/config/lists.ts (87%) rename packages/{types/src => keystone/src/types}/context.ts (95%) rename packages/{types/src => keystone/src/types}/core.ts (100%) create mode 100644 packages/keystone/src/types/filters/enum-filter.ts rename packages/{types/src => keystone/src/types}/filters/index.ts (100%) create mode 100644 packages/keystone/src/types/filters/providers/postgresql.ts create mode 100644 packages/keystone/src/types/filters/providers/sqlite.ts create mode 100644 packages/keystone/src/types/index.ts rename packages/{types/src => keystone/src/types}/json-field-type-polyfill-for-sqlite.ts (83%) rename packages/{types/src => keystone/src/types}/next-fields.ts (70%) rename packages/{types/src => keystone/src/types}/schema/graphql-ts-schema.ts (90%) create mode 100644 packages/keystone/src/types/schema/index.ts create mode 100644 packages/keystone/src/types/schema/schema-api-with-context.d.ts rename packages/{types/src => keystone/src/types}/schema/schema-api-with-context.js (100%) rename packages/{types/src => keystone/src/types}/session.ts (100%) rename packages/{types/src => keystone/src/types}/utils.ts (100%) create mode 100644 packages/keystone/static/admin-error.html create mode 100644 packages/keystone/system/package.json create mode 100644 packages/keystone/testing/package.json create mode 100644 packages/keystone/types/package.json delete mode 100644 packages/types/src/config/access-control.ts delete mode 100644 packages/types/src/filters/enum-filter.ts delete mode 100644 packages/types/src/filters/providers/postgresql.ts delete mode 100644 packages/types/src/filters/providers/sqlite.ts delete mode 100644 packages/types/src/schema/index.ts delete mode 100644 packages/types/src/schema/schema-api-with-context.d.ts create mode 100644 prisma-utils/CHANGELOG.md create mode 100644 tests/admin-ui-tests/list-view-crud.test.ts create mode 100644 tests/admin-ui-tests/navigation.test.ts create mode 100644 tests/api-tests/access-control/authed-user.test.ts delete mode 100644 tests/api-tests/access-control/authed.test.ts create mode 100644 tests/api-tests/access-control/field-access.test.ts create mode 100644 tests/api-tests/access-control/list-access.test.ts rename tests/api-tests/access-control/{mutations-field-static.test.ts => mutations-field.test.ts} (94%) rename tests/api-tests/access-control/{mutations-list-declarative.test.ts => mutations-list-filter.test.ts} (91%) rename tests/api-tests/access-control/{mutations-list-static.test.ts => mutations-list-item.test.ts} (90%) delete mode 100644 tests/api-tests/access-control/not-authed.test.ts create mode 100644 tests/api-tests/access-control/schema-utils.ts create mode 100644 tests/api-tests/extend-express-app.test.ts diff --git a/.changeset/brave-paws-sneeze.md b/.changeset/brave-paws-sneeze.md deleted file mode 100644 index 04d53b8ba95..00000000000 --- a/.changeset/brave-paws-sneeze.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@keystone-next/cloudinary": major -"@keystone-next/fields": major -"@keystone-next/keystone": major -"@keystone-next/types": major ---- - -Removed unused legacy filter code diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 9e112a62ae4..45a87bd161e 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -1,5 +1,5 @@ { - "packages": ["packages/*"], + "packages": ["packages/*", "design-system/packages/*"], "sandboxes": ["/examples/sandbox"], "node": "14" } diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000000..7d5aab78be4 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,2 @@ +ARG VARIANT="14-buster" +FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..ff69de60118 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "Keystone", + "build": { + "dockerfile": "Dockerfile", + "args": { + "VARIANT": "14" + } + }, + + "settings": {}, + + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "gamunu.vscode-yarn", + "prisma.prisma" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + "postCreateCommand": "yarn install", + + "remoteUser": "node" +} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fb9ea6031fd..4b9ae0f3e2c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -314,7 +314,7 @@ jobs: DATABASE_URL: 'file:./test.db' strategy: matrix: - test: ['init.test.ts'] + test: ['init.test.ts', 'list-view-crud.test.ts', 'navigation.test.ts'] fail-fast: false steps: - name: Checkout Repo diff --git a/.gitignore b/.gitignore index 6206b2a725b..2cd433d9a07 100644 --- a/.gitignore +++ b/.gitignore @@ -121,6 +121,7 @@ temp/ # SQLite databases *.db +*.db-journal # Generated files from build process robots.txt diff --git a/design-system/packages/button/CHANGELOG.md b/design-system/packages/button/CHANGELOG.md index 8f032e8d957..644218fd134 100644 --- a/design-system/packages/button/CHANGELOG.md +++ b/design-system/packages/button/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-ui/button +## 5.0.1 + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/core@3.2.0 + - @keystone-ui/icons@4.0.1 + - @keystone-ui/loading@4.0.1 + ## 5.0.0 ### Major Changes diff --git a/design-system/packages/button/package.json b/design-system/packages/button/package.json index 5f81ce360d2..03921b70508 100644 --- a/design-system/packages/button/package.json +++ b/design-system/packages/button/package.json @@ -1,17 +1,17 @@ { "name": "@keystone-ui/button", - "version": "5.0.0", + "version": "5.0.1", "license": "MIT", "main": "dist/button.cjs.js", "module": "dist/button.esm.js", "devDependencies": { - "@types/react": "^17.0.18" + "@types/react": "^17.0.19" }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-ui/core": "^3.0.0", - "@keystone-ui/icons": "^4.0.0", - "@keystone-ui/loading": "^4.0.0", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/icons": "^4.0.1", + "@keystone-ui/loading": "^4.0.1", "react": "^17.0.2" }, "engines": { diff --git a/design-system/packages/button/src/Button.tsx b/design-system/packages/button/src/Button.tsx index 22da02d8b35..47449de6abb 100644 --- a/design-system/packages/button/src/Button.tsx +++ b/design-system/packages/button/src/Button.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ReactNode, useContext } from 'react'; diff --git a/design-system/packages/button/src/hooks/button.ts b/design-system/packages/button/src/hooks/button.ts index cfd30690516..b53ceb51b6c 100644 --- a/design-system/packages/button/src/hooks/button.ts +++ b/design-system/packages/button/src/hooks/button.ts @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { useTheme } from '@keystone-ui/core'; diff --git a/design-system/packages/core/CHANGELOG.md b/design-system/packages/core/CHANGELOG.md index dd989e15242..e1a12d85642 100644 --- a/design-system/packages/core/CHANGELOG.md +++ b/design-system/packages/core/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-ui/core +## 3.2.0 + +### Minor Changes + +- [#6453](https://github.com/keystonejs/keystone/pull/6453) [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Added functionality to ensure that Inline elements that are 'ul' or 'ol' automatically wrap children in 'li' rather than 'div' + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + ## 3.1.1 ### Patch Changes diff --git a/design-system/packages/core/package.json b/design-system/packages/core/package.json index 672d1c3ff4d..dfae6a79f39 100644 --- a/design-system/packages/core/package.json +++ b/design-system/packages/core/package.json @@ -1,11 +1,11 @@ { "name": "@keystone-ui/core", - "version": "3.1.1", + "version": "3.2.0", "license": "MIT", "main": "dist/core.cjs.js", "module": "dist/core.esm.js", "devDependencies": { - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/design-system/packages/core/src/components/Box.tsx b/design-system/packages/core/src/components/Box.tsx index 517a93f4b81..5ef4d7e44a0 100644 --- a/design-system/packages/core/src/components/Box.tsx +++ b/design-system/packages/core/src/components/Box.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '../emotion'; diff --git a/design-system/packages/core/src/components/Center.tsx b/design-system/packages/core/src/components/Center.tsx index 1e65ff234be..9ccbf66b9ea 100644 --- a/design-system/packages/core/src/components/Center.tsx +++ b/design-system/packages/core/src/components/Center.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '../emotion'; diff --git a/design-system/packages/core/src/components/Core.tsx b/design-system/packages/core/src/components/Core.tsx index 2ef411bf15c..b24296eff34 100644 --- a/design-system/packages/core/src/components/Core.tsx +++ b/design-system/packages/core/src/components/Core.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { Fragment, ReactNode } from 'react'; import { jsx, Global } from '../emotion'; diff --git a/design-system/packages/core/src/components/Divider.tsx b/design-system/packages/core/src/components/Divider.tsx index fd629843560..5e477e735e4 100644 --- a/design-system/packages/core/src/components/Divider.tsx +++ b/design-system/packages/core/src/components/Divider.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '../emotion'; diff --git a/design-system/packages/core/src/components/Heading.tsx b/design-system/packages/core/src/components/Heading.tsx index 6bf56d51a46..0bd1eead564 100644 --- a/design-system/packages/core/src/components/Heading.tsx +++ b/design-system/packages/core/src/components/Heading.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '../emotion'; diff --git a/design-system/packages/core/src/components/Inline.tsx b/design-system/packages/core/src/components/Inline.tsx index f4ee25dc719..4b5a9cdaa67 100644 --- a/design-system/packages/core/src/components/Inline.tsx +++ b/design-system/packages/core/src/components/Inline.tsx @@ -1,9 +1,10 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Children, ReactNode } from 'react'; import { jsx } from '../emotion'; -import { forwardRefWithAs } from '../utils'; +import { forwardRefWithAs, getChildTag } from '../utils'; import { Theme } from '../types'; import { useTheme } from '../theme'; import { Box, BoxProps } from './Box'; @@ -29,6 +30,7 @@ export const Inline = forwardRefWithAs<'div', InlineProps>( const { spacing } = useTheme(); const resolvedAlign = alignment[align]; const resolvedGap = spacing[gap]; + const ChildWrapper = getChildTag(props.as); return ( ( > {Children.map(children, child => child !== null && child !== undefined ? ( -

    diff --git a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx index cec664c2356..6b835cae8ae 100644 --- a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx +++ b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx @@ -60,8 +60,8 @@ Delete the `/pages/api` directory. We’ll add a GraphQL API later in the tutori ```text . └── pages -   ├── _app.tsx -   └── index.tsx + ├── _app.tsx + └── index.tsx ``` ### Start your local server @@ -128,18 +128,25 @@ export default config({ ### Add Keystone to Next.js config -Add a `next.config.js` file to your project root with the following: - -```tsx +Edit the `next.config.js` file in your project root with the following: +```diff // next.config.js -const { withKeystone } = require('@keystone-next/keystone/next'); +/** @type {import('next').NextConfig} */ + +- module.exports = { +- reactStrictMode: true, +- } + ++ const { withKeystone } = require("@keystone-next/keystone/next"); -module.exports = withKeystone(); ++ module.exports = withKeystone({ ++ reactStrictMode: true, ++ }); ``` -This is where the magic happens – the `withKeystone` function lets Next.js encapsulate Keystone in its script runtime, while Keystone still operates independently of the Next.js frontend ✨ +This is where the magic happens – the `withKeystone` function lets Next.js encapsulate Keystone in its script runtime, while Keystone still operates independently of the Next.js frontend ✨ ### Update package scripts @@ -149,8 +156,9 @@ Finally, make a small change to the `scripts` object in `package.json` to includ "scripts": { + "postinstall": "keystone-next postinstall", "dev": "next dev", + "build": "next build", "start": "next start", - "build": "next build" + "lint": "next lint" }, ``` diff --git a/docs/pages/docs/walkthroughs/index.tsx b/docs/pages/docs/walkthroughs/index.tsx index c6a5e3bd8be..68c26505d10 100644 --- a/docs/pages/docs/walkthroughs/index.tsx +++ b/docs/pages/docs/walkthroughs/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@emotion/react'; diff --git a/docs/pages/ds.tsx b/docs/pages/ds.tsx index b47d461d437..c05297973ba 100644 --- a/docs/pages/ds.tsx +++ b/docs/pages/ds.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, useState } from 'react'; import { jsx } from '@emotion/react'; diff --git a/docs/pages/index.tsx b/docs/pages/index.tsx index 47f7c55c695..e0ed250039b 100644 --- a/docs/pages/index.tsx +++ b/docs/pages/index.tsx @@ -420,8 +420,8 @@ export default function IndexPage() { - {`import { createSchema, list } from '@keystone-next/keystone/schema'; -import { document, text, timestamp, password, relationship } from '@keystone-next/fields'; + {`import { createSchema, list } from '@keystone-next/keystone'; +import { document, text, timestamp, password, relationship } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Post: list({ @@ -435,7 +435,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), password: password(), posts: relationship({ ref: 'Post.author', many: true }), }, diff --git a/docs/pages/updates/new-access-control.mdx b/docs/pages/updates/new-access-control.mdx new file mode 100644 index 00000000000..a76359bf146 --- /dev/null +++ b/docs/pages/updates/new-access-control.mdx @@ -0,0 +1,181 @@ +import { Markdown, getServerSideProps } from '../../components/Markdown'; +import { Emoji } from '../../components/primitives/Emoji'; + +# A new & improved Access Control API + +Securing the data in your Keystone sytem is one of the most important steps in preparing your application for a production deployment. +To make this process simpler and safer, we've made some important changes to the [Access Control APIs](/docs/apis/access-control) from previous versions. +This document outlines the motivation behind the changes, and shows you how to update your existing Access Control functions to use the new APIs. + +## Control your GrahpQL API + +Previous versions of Keystone allowed you to control which operations were included in your GraphQL API by specifying **static** access control. +For example, the following access control definition would omit all delete operations for the list from the GraphQL API. + +```typescript +import { config, createSchema, list } from '@keystone-next/keystone'; + +export default config({ + lists: createSchema({ + ListKey: list({ + access: { + delete: false, + }, + }), + }), +}); +``` + +With the new API, access control will never have any effect on which operations are in your GraphQL API. + +If you would like to exclude an operation from the GraphQL API, you can use the new [`config.graphql.omit`](/docs/apis/schema#graphql) API. +To exclude all `delete` operations, you would write: + +```typescript +import { config, createSchema, list } from '@keystone-next/keystone'; + +export default config({ + lists: createSchema({ + ListKey: list({ + graphql: { + omit: ['delete'], + } + }), + }), +}); +``` + +!> If you have used static access control to exclude operations from you GraphQL API, update those lists to use the `graphql.omit` configuration option instead. + +## Queries never throw Access Denied + +Previous versions of Keystone would return an Access Denied error from a **query** if an item couldn't be found, or explicitly had access denied. +This behaviour proved confusing, particularly in the missing data case. + +The new access control API **never** returns an Access Denied error on a **query**. +When querying for a single item, if the item is missing, or access is denied, the query will return `null`. +If querying for multiple items, or for a count of items, any items which are excluded due to access control will be filtered out of the result, and removed from the count. +The query will never return an Access Denied error. + +!> If you have client-side code which checks for Access Denied errors on queries, update it to check for `null` return values instead. + +## More flexible access control definitions + +Previous versions of Keystone allowed you to write access control using **static**, **imperative**, or **declarative** definitions. +In practice, these alternatives were not very intuitive to use, and often lead to confusion, which in turn could lead to security risks. + +The new API makes each rule much more explicit and supports fewer variations, making it easier to read, write, and maintain your access control rules. +This in turn will reduce the risk of introducing security gaps in your system. + +Before moving on, be sure to [read the docs](/docs/apis/access-control) for the new API. + +### Updating static access control + +If you are using **static** access control, you will generally want to update this to use the new `operation` level access control. +If you previously had the following: + +```typescript +import { config, createSchema, list } from '@keystone-next/keystone'; + +export default config({ + lists: createSchema({ + ListKey: list({ + access: { + create: false, + read: true, + update: false, + delete: false, + }, + }), + }), +}); +``` + +you will need to change it to: + +```typescript +import { config, createSchema, list } from '@keystone-next/keystone'; + +export default config({ + lists: createSchema({ + ListKey: list({ + access: { + operation: { + create: () => false, + query: () => true, + update: () => false, + delete: () => false, + } + }, + }), + }), +}); +``` + +!> Note that that `read` operation has been renamed to `query`. + +### Updating declarative access control + +If you are using **declarative** access control, you will neeed to update this to use the new `filter` level access control. +If you previously had the following: + +```typescript +import { config, createSchema, list } from '@keystone-next/keystone'; + +export default config({ + lists: createSchema({ + ListKey: list({ + access: { + read: { isAdmin: { equals: true } }, + update: { isAdmin: { equals: true } }, + delete: { isAdmin: { equals: true } }, + }, + }), + }), +}); +``` + +you will need to change it to: + +```typescript +import { config, createSchema, list } from '@keystone-next/keystone'; + +export default config({ + lists: createSchema({ + ListKey: list({ + access: { + filter: { + query: () => ({ isAdmin: { equals: true } }), + update: () => ({ isAdmin: { equals: true } }), + delete: () => ({ isAdmin: { equals: true } }), + } + }, + }), + }), +}); +``` + +### Updating imperative access control + +The **imperative** access control pattern in previous versions of Keystone provided a high degree of flexibility, providing access to a wide range of input variables, and allowing for both static (boolean valued) and declarative (filter valued) return values. +Porting your imperative access control to the new API will depend on what type of function you have. +The following rules will help you decide how to update you system. + +- Does your function ever return a declarative value, e.g. a GraphQL filter value? If so, you should move it into the `filter` access control block. +- Does your function depend on the `item` or `originalInput` arguments? If so, you should move it into the `item` access control block. +- If the function returns a boolean value and does not depend on the `item` or `originalInput` arguments, you should move it into the `operation` access control block. + +!> You can define separate functions for an operation in more than one access control block. Items must pass all access control rules for an operation to be successful. + +## Getting help + +We've put a lot of thought into the new access control APIs based on our experience building real world systems with Keystone. +While large changes like this can be daunting, we hope that the long term benefits will make the transition worth the effort. + +If you get stuck or have questions, reach out to us in the [Keystone community slack](https://community.keystonejs.com) to get the help you need. + +?> The security of the data in your Keystone system should be a high priority. +We strongly encourage you to [write tests](/docs/guides/testing) to verify the behaviour of your access control definitions before upgrading. + +export default ({ children, ...props }) => {children}; +export { getServerSideProps } diff --git a/examples-staging/assets-cloud/CHANGELOG.md b/examples-staging/assets-cloud/CHANGELOG.md index 1a314b62681..b3fe3a3299d 100644 --- a/examples-staging/assets-cloud/CHANGELOG.md +++ b/examples-staging/assets-cloud/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-assets-cloud +## 1.0.5 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 1.0.4 ### Patch Changes diff --git a/examples-staging/assets-cloud/keystone.ts b/examples-staging/assets-cloud/keystone.ts index 1ad503efc60..ff946f754ba 100644 --- a/examples-staging/assets-cloud/keystone.ts +++ b/examples-staging/assets-cloud/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import dotenv from 'dotenv'; import { lists } from './schema'; diff --git a/examples-staging/assets-cloud/package.json b/examples-staging/assets-cloud/package.json index a2b772456eb..c939653f3cb 100644 --- a/examples-staging/assets-cloud/package.json +++ b/examples-staging/assets-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-assets-cloud", - "version": "1.0.4", + "version": "1.0.5", "private": true, "license": "MIT", "scripts": { @@ -9,12 +9,11 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", + "@keystone-next/keystone": "^25.0.0", "dotenv": "^10.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/assets-cloud/schema.graphql b/examples-staging/assets-cloud/schema.graphql index 8441a287b5b..6e73618ef22 100644 --- a/examples-staging/assets-cloud/schema.graphql +++ b/examples-staging/assets-cloud/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -38,6 +41,10 @@ interface FileFieldOutput { src: String! } +input PostWhereUniqueInput { + id: ID +} + type LocalImageFieldOutput implements ImageFieldOutput { id: ID! filesize: Int! @@ -60,11 +67,6 @@ input PostWhereInput { OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: PostStatusTypeNullableFilter - content: StringNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -78,62 +80,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - content: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -205,31 +153,19 @@ type Author { postsCount(where: PostWhereInput! = {}): Int } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -338,6 +274,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/assets-cloud/schema.prisma b/examples-staging/assets-cloud/schema.prisma index 0365e1cd9a8..707e2cced4c 100644 --- a/examples-staging/assets-cloud/schema.prisma +++ b/examples-staging/assets-cloud/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/assets-cloud/schema.ts b/examples-staging/assets-cloud/schema.ts index a1e59c6051b..478a0fd5de2 100644 --- a/examples-staging/assets-cloud/schema.ts +++ b/examples-staging/assets-cloud/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp, image, file } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp, image, file } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Post: list({ @@ -22,7 +22,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), }, }), diff --git a/examples-staging/assets-local/CHANGELOG.md b/examples-staging/assets-local/CHANGELOG.md index f3c8c3c2db4..fe4532cfffa 100644 --- a/examples-staging/assets-local/CHANGELOG.md +++ b/examples-staging/assets-local/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-assets-local +## 1.0.5 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 1.0.4 ### Patch Changes diff --git a/examples-staging/assets-local/keystone.ts b/examples-staging/assets-local/keystone.ts index 827b51d9d88..5d01e6575b5 100644 --- a/examples-staging/assets-local/keystone.ts +++ b/examples-staging/assets-local/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples-staging/assets-local/package.json b/examples-staging/assets-local/package.json index 59aea3525ca..c6a7b6132e5 100644 --- a/examples-staging/assets-local/package.json +++ b/examples-staging/assets-local/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-assets-local", - "version": "1.0.4", + "version": "1.0.5", "private": true, "license": "MIT", "scripts": { @@ -9,11 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/assets-local/schema.graphql b/examples-staging/assets-local/schema.graphql index c98080ea689..c6be74a2179 100644 --- a/examples-staging/assets-local/schema.graphql +++ b/examples-staging/assets-local/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -30,6 +33,10 @@ enum ImageExtension { gif } +input PostWhereUniqueInput { + id: ID +} + type LocalImageFieldOutput implements ImageFieldOutput { id: ID! filesize: Int! @@ -45,11 +52,6 @@ input PostWhereInput { OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: PostStatusTypeNullableFilter - content: StringNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -63,62 +65,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - content: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -183,31 +131,19 @@ type Author { postsCount(where: PostWhereInput! = {}): Int } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -316,6 +252,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/assets-local/schema.prisma b/examples-staging/assets-local/schema.prisma index ecb53606341..4991606a56f 100644 --- a/examples-staging/assets-local/schema.prisma +++ b/examples-staging/assets-local/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/assets-local/schema.ts b/examples-staging/assets-local/schema.ts index dc7dd30e4d9..942a94bb07f 100644 --- a/examples-staging/assets-local/schema.ts +++ b/examples-staging/assets-local/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp, image } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp, image } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Post: list({ @@ -21,7 +21,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), }, }), diff --git a/examples-staging/auth/CHANGELOG.md b/examples-staging/auth/CHANGELOG.md index a8439b3ad63..0daef3afab5 100644 --- a/examples-staging/auth/CHANGELOG.md +++ b/examples-staging/auth/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-auth +## 4.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + ## 4.0.6 ### Patch Changes diff --git a/examples-staging/auth/keystone.ts b/examples-staging/auth/keystone.ts index 61b85b279c3..cac93b7bd83 100644 --- a/examples-staging/auth/keystone.ts +++ b/examples-staging/auth/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import { lists } from './schema'; diff --git a/examples-staging/auth/package.json b/examples-staging/auth/package.json index d3775b189f3..a2e9793f942 100644 --- a/examples-staging/auth/package.json +++ b/examples-staging/auth/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-auth", - "version": "4.0.6", + "version": "4.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,15 +9,14 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/auth": "^31.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "next": "^10.2.3", + "@keystone-next/auth": "^32.0.0", + "@keystone-next/keystone": "^25.0.0", + "next": "^11.1.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/auth/schema.graphql b/examples-staging/auth/schema.graphql index d2c5409d59e..b271487175a 100644 --- a/examples-staging/auth/schema.graphql +++ b/examples-staging/auth/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + input CreateInitialUserInput { name: String email: String @@ -57,15 +60,17 @@ type PasswordState { isSet: Boolean! } +input UserWhereUniqueInput { + id: ID + email: String +} + input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] NOT: [UserWhereInput!] id: IDFilter - name: StringNullableFilter email: StringNullableFilter - password: PasswordFilter - isAdmin: BooleanNullableFilter } input IDFilter { @@ -107,25 +112,8 @@ input NestedStringNullableFilter { not: NestedStringNullableFilter } -input PasswordFilter { - isSet: Boolean! -} - -input BooleanNullableFilter { - equals: Boolean - not: BooleanNullableFilter -} - -input UserWhereUniqueInput { - id: ID - email: String -} - input UserOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection - isAdmin: OrderDirection } enum OrderDirection { @@ -207,6 +195,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/auth/schema.prisma b/examples-staging/auth/schema.prisma index 360b0751600..7e8ccdd031e 100644 --- a/examples-staging/auth/schema.prisma +++ b/examples-staging/auth/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/auth/schema.ts b/examples-staging/auth/schema.ts index 0481f711b94..53fbc34f957 100644 --- a/examples-staging/auth/schema.ts +++ b/examples-staging/auth/schema.ts @@ -1,11 +1,13 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { text, checkbox, password } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { text, checkbox, password } from '@keystone-next/keystone/fields'; export const lists = createSchema({ User: list({ access: { - // Only allow admins to delete users - delete: ({ session }) => session?.data?.isAdmin, + operation: { + // Only allow admins to delete users + delete: ({ session }) => session?.data?.isAdmin, + }, }, ui: { // Since you can't delete users unless you're an admin, we hide the UI for it @@ -19,10 +21,7 @@ export const lists = createSchema({ // The user's name name: text({ isRequired: true }), // The user's email address, used as the identity field for auth - email: text({ - isRequired: true, - isUnique: true, - }), + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), // The user's password, used as the secret field for auth password: password({ access: { diff --git a/examples-staging/basic/CHANGELOG.md b/examples-staging/basic/CHANGELOG.md index 41001b2b185..823198e8a4a 100644 --- a/examples-staging/basic/CHANGELOG.md +++ b/examples-staging/basic/CHANGELOG.md @@ -1,5 +1,20 @@ # @keystone-next/example-app-basic +## 4.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + - @keystone-next/fields-document@9.0.0 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/icons@4.0.1 + - @keystone-ui/tooltip@4.0.2 + ## 4.0.6 ### Patch Changes diff --git a/examples-staging/basic/admin/config.tsx b/examples-staging/basic/admin/config.tsx index e060f6bb678..f41f2254a92 100644 --- a/examples-staging/basic/admin/config.tsx +++ b/examples-staging/basic/admin/config.tsx @@ -1,6 +1,6 @@ // import React from 'react'; -import { AdminConfig } from '@keystone-next/types'; +import { AdminConfig } from '@keystone-next/keystone/types'; // import { DarkTheme } from '@keystone-next/keystone/admin-ui/themes'; // export const theme = DarkTheme; diff --git a/examples-staging/basic/admin/fieldViews/Content.tsx b/examples-staging/basic/admin/fieldViews/Content.tsx index 650ff1db0be..8b74197d9b9 100644 --- a/examples-staging/basic/admin/fieldViews/Content.tsx +++ b/examples-staging/basic/admin/fieldViews/Content.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; import { InfoIcon } from '@keystone-ui/icons/icons/InfoIcon'; diff --git a/examples-staging/basic/admin/fieldViews/Test.tsx b/examples-staging/basic/admin/fieldViews/Test.tsx index 93be56dd024..72ccc49bcf2 100644 --- a/examples-staging/basic/admin/fieldViews/Test.tsx +++ b/examples-staging/basic/admin/fieldViews/Test.tsx @@ -1,9 +1,10 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ -import { FieldProps } from '@keystone-next/types'; +import { FieldProps } from '@keystone-next/keystone/types'; import { jsx } from '@keystone-ui/core'; import { FieldContainer, FieldLabel, TextArea, TextInput } from '@keystone-ui/fields'; -import { controller } from '@keystone-next/fields/types/text/views'; +import { controller } from '@keystone-next/keystone/fields/types/text/views'; export const Field = ({ field, value, onChange, autoFocus }: FieldProps) => ( diff --git a/examples-staging/basic/admin/pages/post/[id].tsx b/examples-staging/basic/admin/pages/post/[id].tsx index 37fa0523607..8820de30cc9 100644 --- a/examples-staging/basic/admin/pages/post/[id].tsx +++ b/examples-staging/basic/admin/pages/post/[id].tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; import { useRouter } from '@keystone-next/keystone/admin-ui/router'; diff --git a/examples-staging/basic/keystone.ts b/examples-staging/basic/keystone.ts index 29d58667ac1..1ae053b3351 100644 --- a/examples-staging/basic/keystone.ts +++ b/examples-staging/basic/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; @@ -29,10 +29,6 @@ export default auth.withAuth( provider: 'sqlite', url: process.env.DATABASE_URL || 'file:./keystone-example.db', }, - // NOTE -- this is not implemented, keystone currently always provides a graphql api at /api/graphql - // graphql: { - // path: '/api/graphql', - // }, ui: { // NOTE -- this is not implemented, keystone currently always provides an admin ui at / // path: '/admin', diff --git a/examples-staging/basic/package.json b/examples-staging/basic/package.json index dfa1fae5fab..08cc8bd250f 100644 --- a/examples-staging/basic/package.json +++ b/examples-staging/basic/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/examples-app-basic", - "version": "4.0.6", + "version": "4.0.7", "private": true, "license": "MIT", "scripts": { @@ -10,27 +10,25 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-next/auth": "^31.0.0", + "@keystone-next/auth": "^32.0.0", "@keystone-next/document-renderer": "^4.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/fields-document": "^8.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.1", - "@keystone-ui/icons": "^4.0.0", - "@keystone-ui/tooltip": "^4.0.1", + "@keystone-next/fields-document": "^9.0.0", + "@keystone-next/keystone": "^25.0.0", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/icons": "^4.0.1", + "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.18", + "@types/react": "^17.0.19", "apollo-server-micro": "^2.25.2", - "graphql": "^15.5.1", + "graphql": "^15.5.2", "graphql-tag": "^2.12.5", - "next": "^10.2.3", + "next": "^11.1.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/basic/schema.graphql b/examples-staging/basic/schema.graphql index 9800f4b99ce..2f3587b414c 100644 --- a/examples-staging/basic/schema.graphql +++ b/examples-staging/basic/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type RandomNumber { number: Int generatedAt: Int @@ -120,6 +123,11 @@ type PasswordState { isSet: Boolean! } +input UserWhereUniqueInput { + id: ID + email: String +} + type LocalImageFieldOutput implements ImageFieldOutput { id: ID! filesize: Int! @@ -142,13 +150,7 @@ input UserWhereInput { OR: [UserWhereInput!] NOT: [UserWhereInput!] id: IDFilter - name: StringNullableFilter email: StringNullableFilter - password: PasswordFilter - isAdmin: BooleanNullableFilter - roles: StringNullableFilter - phoneNumbers: PhoneNumberManyRelationFilter - posts: PostManyRelationFilter } input IDFilter { @@ -190,38 +192,8 @@ input NestedStringNullableFilter { not: NestedStringNullableFilter } -input PasswordFilter { - isSet: Boolean! -} - -input BooleanNullableFilter { - equals: Boolean - not: BooleanNullableFilter -} - -input PhoneNumberManyRelationFilter { - every: PhoneNumberWhereInput - some: PhoneNumberWhereInput - none: PhoneNumberWhereInput -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input UserWhereUniqueInput { - id: ID - email: String -} - input UserOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection - isAdmin: OrderDirection - roles: OrderDirection } enum OrderDirection { @@ -305,24 +277,19 @@ type PhoneNumber { value: String } +input PhoneNumberWhereUniqueInput { + id: ID +} + input PhoneNumberWhereInput { AND: [PhoneNumberWhereInput!] OR: [PhoneNumberWhereInput!] NOT: [PhoneNumberWhereInput!] id: IDFilter - user: UserWhereInput - type: StringNullableFilter - value: StringNullableFilter -} - -input PhoneNumberWhereUniqueInput { - id: ID } input PhoneNumberOrderByInput { id: OrderDirection - type: OrderDirection - value: OrderDirection } input PhoneNumberUpdateInput { @@ -366,37 +333,19 @@ type Post_content_DocumentField { document(hydrateRelationships: Boolean! = false): JSON! } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: StringNullableFilter - publishDate: DateTimeNullableFilter - author: UserWhereInput -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID } input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - publishDate: OrderDirection } input PostUpdateInput { @@ -492,6 +441,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/basic/schema.prisma b/examples-staging/basic/schema.prisma index 1a1eaa6c0bd..d02d00119c1 100644 --- a/examples-staging/basic/schema.prisma +++ b/examples-staging/basic/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/basic/schema.ts b/examples-staging/basic/schema.ts index ea795626295..9cf3fe8eef4 100644 --- a/examples-staging/basic/schema.ts +++ b/examples-staging/basic/schema.ts @@ -1,4 +1,4 @@ -import { createSchema, list, graphQLSchemaExtension, gql } from '@keystone-next/keystone/schema'; +import { createSchema, list, graphQLSchemaExtension, gql } from '@keystone-next/keystone'; import { text, relationship, @@ -9,10 +9,10 @@ import { virtual, image, file, -} from '@keystone-next/fields'; +} from '@keystone-next/keystone/fields'; import { document } from '@keystone-next/fields-document'; // import { cloudinaryImage } from '@keystone-next/cloudinary'; -import { KeystoneListsAPI, schema } from '@keystone-next/types'; +import { KeystoneListsAPI, graphql } from '@keystone-next/keystone/types'; import { componentBlocks } from './admin/fieldViews/Content'; import { KeystoneListsTypeInfo } from '.keystone/types'; @@ -45,7 +45,7 @@ export const lists = createSchema({ /** The user's first and last name. */ name: text({ isRequired: true }), /** Email is used to log into the system. */ - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), /** Avatar upload for the users profile, stored locally */ avatar: image(), attachment: file(), @@ -54,8 +54,8 @@ export const lists = createSchema({ /** Administrators have more access to various lists and fields. */ isAdmin: checkbox({ access: { - create: access.isAdmin, read: access.isAdmin, + create: access.isAdmin, update: access.isAdmin, }, ui: { @@ -84,8 +84,8 @@ export const lists = createSchema({ }), posts: relationship({ ref: 'Post.author', many: true }), randomNumber: virtual({ - field: schema.field({ - type: schema.Float, + field: graphql.field({ + type: graphql.Float, resolve() { return randomNumber(); }, @@ -100,8 +100,8 @@ export const lists = createSchema({ }, fields: { label: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, resolve(item) { return `${item.type} - ${item.value}`; }, diff --git a/examples-staging/ecommerce/CHANGELOG.md b/examples-staging/ecommerce/CHANGELOG.md index 4b1574ed36b..b2857d771a4 100644 --- a/examples-staging/ecommerce/CHANGELOG.md +++ b/examples-staging/ecommerce/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-next/example-ecommerce +## 4.0.8 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/cloudinary@7.0.0 + - @keystone-next/auth@32.0.0 + ## 4.0.7 ### Patch Changes diff --git a/examples-staging/ecommerce/keystone.ts b/examples-staging/ecommerce/keystone.ts index 77c9fa14ee1..303ee2712eb 100644 --- a/examples-staging/ecommerce/keystone.ts +++ b/examples-staging/ecommerce/keystone.ts @@ -1,5 +1,5 @@ import { createAuth } from '@keystone-next/auth'; -import { config, createSchema } from '@keystone-next/keystone/schema'; +import { config, createSchema } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { permissionsList } from './schemas/fields'; import { Role } from './schemas/Role'; diff --git a/examples-staging/ecommerce/mutations/addToCart.ts b/examples-staging/ecommerce/mutations/addToCart.ts index e071e44cd0d..4a9692d93a8 100644 --- a/examples-staging/ecommerce/mutations/addToCart.ts +++ b/examples-staging/ecommerce/mutations/addToCart.ts @@ -1,4 +1,4 @@ -import { KeystoneContext } from '@keystone-next/types'; +import { KeystoneContext } from '@keystone-next/keystone/types'; import { Session } from '../types'; async function addToCart( diff --git a/examples-staging/ecommerce/mutations/checkout.ts b/examples-staging/ecommerce/mutations/checkout.ts index 78645966d40..2e9ce95e1a2 100644 --- a/examples-staging/ecommerce/mutations/checkout.ts +++ b/examples-staging/ecommerce/mutations/checkout.ts @@ -1,4 +1,4 @@ -import { KeystoneContext } from '@keystone-next/types'; +import { KeystoneContext } from '@keystone-next/keystone/types'; // import stripeConfig from '../lib/stripe'; diff --git a/examples-staging/ecommerce/mutations/index.ts b/examples-staging/ecommerce/mutations/index.ts index 39b85742828..a7721eb9015 100644 --- a/examples-staging/ecommerce/mutations/index.ts +++ b/examples-staging/ecommerce/mutations/index.ts @@ -1,4 +1,4 @@ -import { graphQLSchemaExtension } from '@keystone-next/keystone/schema'; +import { graphQLSchemaExtension } from '@keystone-next/keystone'; import addToCart from './addToCart'; import checkout from './checkout'; diff --git a/examples-staging/ecommerce/package.json b/examples-staging/ecommerce/package.json index 4a174a517da..aba0fb440dc 100644 --- a/examples-staging/ecommerce/package.json +++ b/examples-staging/ecommerce/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-ecommerce", - "version": "4.0.7", + "version": "4.0.8", "private": true, "author": "Wes Bos & Jed Watson", "license": "MIT", @@ -16,22 +16,19 @@ "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@babel/runtime": "^7.15.3", - "@keystone-next/auth": "^31.0.0", - "@keystone-next/cloudinary": "^6.0.6", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", + "@keystone-next/auth": "^32.0.0", + "@keystone-next/cloudinary": "^7.0.0", + "@keystone-next/keystone": "^25.0.0", "@types/nodemailer": "^6.4.4", "dotenv": "^10.0.0", - "next": "^10.2.3", + "next": "^11.1.0", "nodemailer": "^6.6.3", "react": "^17.0.2", "react-dom": "^17.0.2", - "stripe": "^8.169.0" + "stripe": "^8.171.0" }, "devDependencies": { - "@keystone-next/testing": "^1.1.1", - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/ecommerce/schema.graphql b/examples-staging/ecommerce/schema.graphql index 4b3d0b5cc08..ede25549b39 100644 --- a/examples-staging/ecommerce/schema.graphql +++ b/examples-staging/ecommerce/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Mutation { addToCart(productId: ID): CartItem checkout(token: String!): Order @@ -167,21 +170,17 @@ type PasswordState { isSet: Boolean! } +input UserWhereUniqueInput { + id: ID + email: String +} + input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] NOT: [UserWhereInput!] id: IDFilter - name: StringNullableFilter email: StringNullableFilter - password: PasswordFilter - cart: CartItemManyRelationFilter - orders: OrderManyRelationFilter - role: RoleWhereInput - products: ProductManyRelationFilter - passwordResetToken: PasswordFilter - passwordResetIssuedAt: DateTimeNullableFilter - passwordResetRedeemedAt: DateTimeNullableFilter } input IDFilter { @@ -223,50 +222,8 @@ input NestedStringNullableFilter { not: NestedStringNullableFilter } -input PasswordFilter { - isSet: Boolean! -} - -input CartItemManyRelationFilter { - every: CartItemWhereInput - some: CartItemWhereInput - none: CartItemWhereInput -} - -input OrderManyRelationFilter { - every: OrderWhereInput - some: OrderWhereInput - none: OrderWhereInput -} - -input ProductManyRelationFilter { - every: ProductWhereInput - some: ProductWhereInput - none: ProductWhereInput -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input UserWhereUniqueInput { - id: ID - email: String -} - input UserOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection - passwordResetIssuedAt: OrderDirection - passwordResetRedeemedAt: OrderDirection } enum OrderDirection { @@ -362,40 +319,19 @@ type Product { user: User } +input ProductWhereUniqueInput { + id: ID +} + input ProductWhereInput { AND: [ProductWhereInput!] OR: [ProductWhereInput!] NOT: [ProductWhereInput!] id: IDFilter - name: StringNullableFilter - description: StringNullableFilter - photo: ProductImageWhereInput - status: StringNullableFilter - price: IntNullableFilter - user: UserWhereInput -} - -input IntNullableFilter { - equals: Int - in: [Int!] - notIn: [Int!] - lt: Int - lte: Int - gt: Int - gte: Int - not: IntNullableFilter -} - -input ProductWhereUniqueInput { - id: ID } input ProductOrderByInput { id: OrderDirection - name: OrderDirection - description: OrderDirection - status: OrderDirection - price: OrderDirection } input ProductUpdateInput { @@ -499,22 +435,19 @@ input CloudinaryImageFormat { transformation: String } +input ProductImageWhereUniqueInput { + id: ID +} + input ProductImageWhereInput { AND: [ProductImageWhereInput!] OR: [ProductImageWhereInput!] NOT: [ProductImageWhereInput!] id: IDFilter - altText: StringNullableFilter - product: ProductWhereInput -} - -input ProductImageWhereUniqueInput { - id: ID } input ProductImageOrderByInput { id: OrderDirection - altText: OrderDirection } input ProductImageUpdateInput { @@ -557,23 +490,21 @@ type CartItem { user: User } +input CartItemWhereUniqueInput { + id: ID +} + input CartItemWhereInput { AND: [CartItemWhereInput!] OR: [CartItemWhereInput!] NOT: [CartItemWhereInput!] id: IDFilter - quantity: IntNullableFilter product: ProductWhereInput user: UserWhereInput } -input CartItemWhereUniqueInput { - id: ID -} - input CartItemOrderByInput { id: OrderDirection - quantity: OrderDirection } input CartItemUpdateInput { @@ -603,29 +534,20 @@ type OrderItem { order: Order } +input OrderItemWhereUniqueInput { + id: ID +} + input OrderItemWhereInput { AND: [OrderItemWhereInput!] OR: [OrderItemWhereInput!] NOT: [OrderItemWhereInput!] id: IDFilter - name: StringNullableFilter - description: StringNullableFilter - photo: ProductImageWhereInput - price: IntNullableFilter - quantity: IntNullableFilter - order: OrderWhereInput -} - -input OrderItemWhereUniqueInput { - id: ID } input OrderItemOrderByInput { id: OrderDirection name: OrderDirection - description: OrderDirection - price: OrderDirection - quantity: OrderDirection } input OrderItemUpdateInput { @@ -677,31 +599,19 @@ type Order { charge: String } +input OrderWhereUniqueInput { + id: ID +} + input OrderWhereInput { AND: [OrderWhereInput!] OR: [OrderWhereInput!] NOT: [OrderWhereInput!] id: IDFilter - total: IntNullableFilter - items: OrderItemManyRelationFilter - user: UserWhereInput - charge: StringNullableFilter -} - -input OrderItemManyRelationFilter { - every: OrderItemWhereInput - some: OrderItemWhereInput - none: OrderItemWhereInput -} - -input OrderWhereUniqueInput { - id: ID } input OrderOrderByInput { id: OrderDirection - total: OrderDirection - charge: OrderDirection } input OrderUpdateInput { @@ -753,45 +663,19 @@ type Role { assignedToCount(where: UserWhereInput! = {}): Int } +input RoleWhereUniqueInput { + id: ID +} + input RoleWhereInput { AND: [RoleWhereInput!] OR: [RoleWhereInput!] NOT: [RoleWhereInput!] id: IDFilter - name: StringNullableFilter - canManageProducts: BooleanNullableFilter - canSeeOtherUsers: BooleanNullableFilter - canManageUsers: BooleanNullableFilter - canManageRoles: BooleanNullableFilter - canManageCart: BooleanNullableFilter - canManageOrders: BooleanNullableFilter - assignedTo: UserManyRelationFilter -} - -input BooleanNullableFilter { - equals: Boolean - not: BooleanNullableFilter -} - -input UserManyRelationFilter { - every: UserWhereInput - some: UserWhereInput - none: UserWhereInput -} - -input RoleWhereUniqueInput { - id: ID } input RoleOrderByInput { id: OrderDirection - name: OrderDirection - canManageProducts: OrderDirection - canSeeOtherUsers: OrderDirection - canManageUsers: OrderDirection - canManageRoles: OrderDirection - canManageCart: OrderDirection - canManageOrders: OrderDirection } input RoleUpdateInput { @@ -940,6 +824,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/ecommerce/schema.prisma b/examples-staging/ecommerce/schema.prisma index 6b2baa8c881..b2d19d2f554 100644 --- a/examples-staging/ecommerce/schema.prisma +++ b/examples-staging/ecommerce/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/ecommerce/schemas/CartItem.ts b/examples-staging/ecommerce/schemas/CartItem.ts index 680232582e2..211583ff810 100644 --- a/examples-staging/ecommerce/schemas/CartItem.ts +++ b/examples-staging/ecommerce/schemas/CartItem.ts @@ -1,13 +1,17 @@ -import { integer, relationship } from '@keystone-next/fields'; -import { list } from '@keystone-next/keystone/schema'; +import { integer, relationship } from '@keystone-next/keystone/fields'; +import { list } from '@keystone-next/keystone'; import { rules, isSignedIn } from '../access'; export const CartItem = list({ access: { - create: isSignedIn, - read: rules.canOrder, - update: rules.canOrder, - delete: rules.canOrder, + operation: { + create: isSignedIn, + }, + filter: { + query: rules.canOrder, + update: rules.canOrder, + delete: rules.canOrder, + }, }, ui: { listView: { @@ -20,7 +24,7 @@ export const CartItem = list({ defaultValue: 1, isRequired: true, }), - product: relationship({ ref: 'Product' }), - user: relationship({ ref: 'User.cart' }), + product: relationship({ ref: 'Product', isFilterable: true }), + user: relationship({ ref: 'User.cart', isFilterable: true }), }, }); diff --git a/examples-staging/ecommerce/schemas/Order.ts b/examples-staging/ecommerce/schemas/Order.ts index 36b7d1f4df6..0f9dc0a08cd 100644 --- a/examples-staging/ecommerce/schemas/Order.ts +++ b/examples-staging/ecommerce/schemas/Order.ts @@ -1,20 +1,22 @@ -import { integer, text, relationship, virtual } from '@keystone-next/fields'; -import { list } from '@keystone-next/keystone/schema'; -import { schema } from '@keystone-next/types'; +import { integer, text, relationship, virtual } from '@keystone-next/keystone/fields'; +import { list } from '@keystone-next/keystone'; +import { graphql } from '@keystone-next/keystone/types'; import { isSignedIn, rules } from '../access'; import formatMoney from '../lib/formatMoney'; export const Order = list({ access: { - create: isSignedIn, - read: rules.canOrder, - update: () => false, - delete: () => false, + operation: { + create: isSignedIn, + update: () => false, + delete: () => false, + }, + filter: { query: rules.canOrder }, }, fields: { label: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, resolve(item) { return `${formatMoney((item as any).total)}`; }, diff --git a/examples-staging/ecommerce/schemas/OrderItem.ts b/examples-staging/ecommerce/schemas/OrderItem.ts index 60458995d5a..a65f9237e32 100644 --- a/examples-staging/ecommerce/schemas/OrderItem.ts +++ b/examples-staging/ecommerce/schemas/OrderItem.ts @@ -1,16 +1,20 @@ -import { integer, text, relationship } from '@keystone-next/fields'; -import { list } from '@keystone-next/keystone/schema'; +import { integer, text, relationship } from '@keystone-next/keystone/fields'; +import { list } from '@keystone-next/keystone'; import { isSignedIn, rules } from '../access'; export const OrderItem = list({ access: { - create: isSignedIn, - read: rules.canManageOrderItems, - update: () => false, - delete: () => false, + operation: { + create: isSignedIn, + update: () => false, + delete: () => false, + }, + filter: { + query: rules.canManageOrderItems, + }, }, fields: { - name: text({ isRequired: true }), + name: text({ isRequired: true, isOrderable: true }), description: text({ ui: { displayMode: 'textarea', diff --git a/examples-staging/ecommerce/schemas/Product.ts b/examples-staging/ecommerce/schemas/Product.ts index 8a376544fee..fa0fce7b43f 100644 --- a/examples-staging/ecommerce/schemas/Product.ts +++ b/examples-staging/ecommerce/schemas/Product.ts @@ -1,13 +1,17 @@ -import { integer, select, text, relationship } from '@keystone-next/fields'; -import { list } from '@keystone-next/keystone/schema'; +import { integer, select, text, relationship } from '@keystone-next/keystone/fields'; +import { list } from '@keystone-next/keystone'; import { rules, isSignedIn } from '../access'; export const Product = list({ access: { - create: isSignedIn, - read: rules.canReadProducts, - update: rules.canManageProducts, - delete: rules.canManageProducts, + operation: { + create: isSignedIn, + }, + filter: { + query: rules.canReadProducts, + update: rules.canManageProducts, + delete: rules.canManageProducts, + }, }, fields: { name: text({ isRequired: true }), diff --git a/examples-staging/ecommerce/schemas/ProductImage.ts b/examples-staging/ecommerce/schemas/ProductImage.ts index 928985adf7b..8ed89257db5 100644 --- a/examples-staging/ecommerce/schemas/ProductImage.ts +++ b/examples-staging/ecommerce/schemas/ProductImage.ts @@ -1,6 +1,6 @@ import 'dotenv/config'; -import { relationship, text } from '@keystone-next/fields'; -import { list } from '@keystone-next/keystone/schema'; +import { relationship, text } from '@keystone-next/keystone/fields'; +import { list } from '@keystone-next/keystone'; import { cloudinaryImage } from '@keystone-next/cloudinary'; import { isSignedIn, permissions } from '../access'; @@ -13,10 +13,12 @@ export const cloudinary = { export const ProductImage = list({ access: { - create: isSignedIn, - read: () => true, - update: permissions.canManageProducts, - delete: permissions.canManageProducts, + operation: { + create: isSignedIn, + query: () => true, + update: permissions.canManageProducts, + delete: permissions.canManageProducts, + }, }, fields: { image: cloudinaryImage({ diff --git a/examples-staging/ecommerce/schemas/Role.ts b/examples-staging/ecommerce/schemas/Role.ts index 5a8be066525..78ab5f2b57c 100644 --- a/examples-staging/ecommerce/schemas/Role.ts +++ b/examples-staging/ecommerce/schemas/Role.ts @@ -1,14 +1,16 @@ -import { relationship, text } from '@keystone-next/fields'; -import { list } from '@keystone-next/keystone/schema'; +import { relationship, text } from '@keystone-next/keystone/fields'; +import { list } from '@keystone-next/keystone'; import { permissions } from '../access'; import { permissionFields } from './fields'; export const Role = list({ access: { - create: permissions.canManageRoles, - read: permissions.canManageRoles, - update: permissions.canManageRoles, - delete: permissions.canManageRoles, + operation: { + create: permissions.canManageRoles, + query: permissions.canManageRoles, + update: permissions.canManageRoles, + delete: permissions.canManageRoles, + }, }, ui: { hideCreate: args => !permissions.canManageRoles(args), diff --git a/examples-staging/ecommerce/schemas/User.ts b/examples-staging/ecommerce/schemas/User.ts index 438be88bfc6..6b205ba166a 100644 --- a/examples-staging/ecommerce/schemas/User.ts +++ b/examples-staging/ecommerce/schemas/User.ts @@ -1,15 +1,19 @@ -import { list } from '@keystone-next/keystone/schema'; -import { text, password, relationship } from '@keystone-next/fields'; +import { list } from '@keystone-next/keystone'; +import { text, password, relationship } from '@keystone-next/keystone/fields'; import { permissions, rules } from '../access'; export const User = list({ access: { - create: () => true, - read: rules.canManageUsers, - update: rules.canManageUsers, - // only people with the permission can delete themselves! - // You can't delete yourself - delete: permissions.canManageUsers, + operation: { + create: () => true, + // only people with the permission can delete themselves! + // You can't delete yourself + delete: permissions.canManageUsers, + }, + filter: { + query: rules.canManageUsers, + update: rules.canManageUsers, + }, }, ui: { // hide the backend UI from regular users @@ -18,7 +22,7 @@ export const User = list({ }, fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), password: password(), cart: relationship({ ref: 'CartItem.user', diff --git a/examples-staging/ecommerce/schemas/fields.ts b/examples-staging/ecommerce/schemas/fields.ts index 1a8c0a29824..8cdb67a7f3f 100644 --- a/examples-staging/ecommerce/schemas/fields.ts +++ b/examples-staging/ecommerce/schemas/fields.ts @@ -1,4 +1,4 @@ -import { checkbox } from '@keystone-next/fields'; +import { checkbox } from '@keystone-next/keystone/fields'; export const permissionFields = { canManageProducts: checkbox({ diff --git a/examples-staging/ecommerce/seed-data/index.ts b/examples-staging/ecommerce/seed-data/index.ts index 68ae3a09560..318d56bb162 100644 --- a/examples-staging/ecommerce/seed-data/index.ts +++ b/examples-staging/ecommerce/seed-data/index.ts @@ -1,4 +1,4 @@ -import { KeystoneContext } from '@keystone-next/types'; +import { KeystoneContext } from '@keystone-next/keystone/types'; import { products } from './data'; export async function insertSeedData({ prisma }: KeystoneContext) { diff --git a/examples-staging/ecommerce/tests/mutations.test.ts b/examples-staging/ecommerce/tests/mutations.test.ts index 6a114e9ea51..f3f425b175d 100644 --- a/examples-staging/ecommerce/tests/mutations.test.ts +++ b/examples-staging/ecommerce/tests/mutations.test.ts @@ -1,5 +1,5 @@ -import { KeystoneContext } from '@keystone-next/types'; -import { setupTestRunner } from '@keystone-next/testing'; +import { KeystoneContext } from '@keystone-next/keystone/types'; +import { setupTestRunner } from '@keystone-next/keystone/testing'; import config from '../keystone'; const FAKE_ID = 'cinjfgbkjnfg'; diff --git a/examples-staging/ecommerce/types.ts b/examples-staging/ecommerce/types.ts index ee1f06f44c2..20cf767d0d3 100644 --- a/examples-staging/ecommerce/types.ts +++ b/examples-staging/ecommerce/types.ts @@ -1,4 +1,4 @@ -import { KeystoneGraphQLAPI, KeystoneListsAPI } from '@keystone-next/types'; +import { KeystoneGraphQLAPI, KeystoneListsAPI } from '@keystone-next/keystone/types'; // NOTE -- these types are commented out in master because they aren't generated by the build (yet) // To get full List and GraphQL API type support, uncomment them here and use them below diff --git a/examples-staging/embedded-nextjs/CHANGELOG.md b/examples-staging/embedded-nextjs/CHANGELOG.md index 9e03eb1293c..a9f760120c4 100644 --- a/examples-staging/embedded-nextjs/CHANGELOG.md +++ b/examples-staging/embedded-nextjs/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-next-lite +## 3.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 3.0.6 ### Patch Changes diff --git a/examples-staging/embedded-nextjs/keystone.ts b/examples-staging/embedded-nextjs/keystone.ts index cd02fa088d1..1788ff9b17f 100644 --- a/examples-staging/embedded-nextjs/keystone.ts +++ b/examples-staging/embedded-nextjs/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { Post } from './schema'; diff --git a/examples-staging/embedded-nextjs/package.json b/examples-staging/embedded-nextjs/package.json index 54d6edeac8c..709adba8534 100644 --- a/examples-staging/embedded-nextjs/package.json +++ b/examples-staging/embedded-nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-embedded-nextjs", - "version": "3.0.6", + "version": "3.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,15 +9,14 @@ "build": "next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", + "@keystone-next/keystone": "^25.0.0", "dotenv": "^10.0.0", - "next": "^10.2.3", + "next": "^11.1.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/embedded-nextjs/schema.graphql b/examples-staging/embedded-nextjs/schema.graphql index 0c723ddb1de..b00789c9cf7 100644 --- a/examples-staging/embedded-nextjs/schema.graphql +++ b/examples-staging/embedded-nextjs/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -5,14 +8,15 @@ type Post { content: String } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - slug: StringNullableFilter - content: StringNullableFilter } input IDFilter { @@ -26,43 +30,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - slug: OrderDirection - content: OrderDirection } enum OrderDirection { @@ -150,6 +119,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/embedded-nextjs/schema.prisma b/examples-staging/embedded-nextjs/schema.prisma index b9f5b385fb9..9b3627a0753 100644 --- a/examples-staging/embedded-nextjs/schema.prisma +++ b/examples-staging/embedded-nextjs/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/embedded-nextjs/schema.ts b/examples-staging/embedded-nextjs/schema.ts index dfae7606ec5..68b772c2059 100644 --- a/examples-staging/embedded-nextjs/schema.ts +++ b/examples-staging/embedded-nextjs/schema.ts @@ -1,5 +1,5 @@ -import { list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export const Post = list({ fields: { diff --git a/examples-staging/graphql-api-endpoint/CHANGELOG.md b/examples-staging/graphql-api-endpoint/CHANGELOG.md index 3ba38d49da6..5d9c376d88a 100644 --- a/examples-staging/graphql-api-endpoint/CHANGELOG.md +++ b/examples-staging/graphql-api-endpoint/CHANGELOG.md @@ -1,5 +1,14 @@ # keystone-next-app +## 1.0.7 + +### Patch Changes + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + - @keystone-next/fields-document@9.0.0 + ## 1.0.6 ### Patch Changes diff --git a/examples-staging/graphql-api-endpoint/keystone.ts b/examples-staging/graphql-api-endpoint/keystone.ts index 15b4c87615f..13357e28f09 100644 --- a/examples-staging/graphql-api-endpoint/keystone.ts +++ b/examples-staging/graphql-api-endpoint/keystone.ts @@ -1,6 +1,6 @@ import { statelessSessions } from '@keystone-next/keystone/session'; -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { createAuth } from '@keystone-next/auth'; import { lists } from './schema'; diff --git a/examples-staging/graphql-api-endpoint/package.json b/examples-staging/graphql-api-endpoint/package.json index 11958b4f72c..687922c8585 100644 --- a/examples-staging/graphql-api-endpoint/package.json +++ b/examples-staging/graphql-api-endpoint/package.json @@ -1,6 +1,6 @@ { "name": "keystone-next-app", - "version": "1.0.6", + "version": "1.0.7", "private": true, "scripts": { "dev": "keystone-next dev", @@ -12,10 +12,9 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-next/auth": "^31.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/fields-document": "^8.0.0", - "@keystone-next/keystone": "^24.0.0", + "@keystone-next/auth": "^32.0.0", + "@keystone-next/fields-document": "^9.0.0", + "@keystone-next/keystone": "^25.0.0", "apollo-server-micro": "^2.25.2" }, "repository": "https://github.com/keystonejs/keystone/tree/master/examples-staging/graphql-api-endpoint" diff --git a/examples-staging/graphql-api-endpoint/schema.graphql b/examples-staging/graphql-api-endpoint/schema.graphql index 1203d46c607..3caa70617f4 100644 --- a/examples-staging/graphql-api-endpoint/schema.graphql +++ b/examples-staging/graphql-api-endpoint/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + input CreateInitialUserInput { name: String email: String @@ -75,15 +78,17 @@ type PasswordState { isSet: Boolean! } +input UserWhereUniqueInput { + id: ID + email: String +} + input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] NOT: [UserWhereInput!] id: IDFilter - name: StringNullableFilter email: StringNullableFilter - password: PasswordFilter - posts: PostManyRelationFilter } input IDFilter { @@ -131,25 +136,8 @@ input NestedStringNullableFilter { not: NestedStringNullableFilter } -input PasswordFilter { - isSet: Boolean! -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input UserWhereUniqueInput { - id: ID - email: String -} - input UserOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } enum OrderDirection { @@ -208,44 +196,19 @@ type Post_content_DocumentField { document(hydrateRelationships: Boolean! = false): JSON! } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: StringNullableFilter - publishDate: DateTimeNullableFilter - author: UserWhereInput - tags: TagManyRelationFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input TagManyRelationFilter { - every: TagWhereInput - some: TagWhereInput - none: TagWhereInput -} - -input PostWhereUniqueInput { - id: ID } input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - publishDate: OrderDirection } input PostUpdateInput { @@ -306,22 +269,19 @@ type Tag { postsCount(where: PostWhereInput! = {}): Int } +input TagWhereUniqueInput { + id: ID +} + input TagWhereInput { AND: [TagWhereInput!] OR: [TagWhereInput!] NOT: [TagWhereInput!] id: IDFilter - name: StringNullableFilter - posts: PostManyRelationFilter -} - -input TagWhereUniqueInput { - id: ID } input TagOrderByInput { id: OrderDirection - name: OrderDirection } input TagUpdateInput { @@ -410,6 +370,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/graphql-api-endpoint/schema.prisma b/examples-staging/graphql-api-endpoint/schema.prisma index c62fc0489f1..24735e8e91b 100644 --- a/examples-staging/graphql-api-endpoint/schema.prisma +++ b/examples-staging/graphql-api-endpoint/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource postgresql { url = env("DATABASE_URL") provider = "postgresql" diff --git a/examples-staging/graphql-api-endpoint/schema.ts b/examples-staging/graphql-api-endpoint/schema.ts index 820f9cfec00..6a5e5e3f765 100644 --- a/examples-staging/graphql-api-endpoint/schema.ts +++ b/examples-staging/graphql-api-endpoint/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { text, relationship, password, timestamp, select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { text, relationship, password, timestamp, select } from '@keystone-next/keystone/fields'; import { document } from '@keystone-next/fields-document'; export const lists = createSchema({ @@ -11,7 +11,7 @@ export const lists = createSchema({ }, fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), password: password(), posts: relationship({ ref: 'Post.author', many: true }), }, diff --git a/examples-staging/playground/CHANGELOG.md b/examples-staging/playground/CHANGELOG.md index fe7a35f17b9..46db53e1b83 100644 --- a/examples-staging/playground/CHANGELOG.md +++ b/examples-staging/playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-next/example-playground +## 1.0.6 + +### Patch Changes + +- [#6391](https://github.com/keystonejs/keystone/pull/6391) [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41) Thanks [@bladey](https://github.com/bladey)! - Adds support for `introspection` in the Apollo Server config. Introspection enables you to query a GraphQL server for information about the underlying schema. If the playground is enabled then introspection is automatically enabled - unless specifically disabled. + +* [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +* Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 1.0.5 ### Patch Changes diff --git a/examples-staging/playground/keystone.ts b/examples-staging/playground/keystone.ts index 39e754b0230..9eb0eb1ed8d 100644 --- a/examples-staging/playground/keystone.ts +++ b/examples-staging/playground/keystone.ts @@ -1,7 +1,7 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; -// graphql.apolloConfig.playground === false (playground not accessible in all cases) +// graphql.apolloConfig.playground === false (playground not accessible in all cases, introspection will be disabled by default) // export default config({ // db: { // provider: 'sqlite', @@ -15,7 +15,7 @@ import { lists } from './schema'; // } // }); -// graphql.apolloConfig.playground === true (playground accessible in all cases) +// graphql.apolloConfig.playground === true (playground accessible in all cases, introspection will be enabled by default) // export default config({ // db: { // provider: 'sqlite', @@ -25,11 +25,26 @@ import { lists } from './schema'; // graphql: { // apolloConfig: { // playground: true, -// } -// } +// }, +// }, +// }); + +// graphql.apolloConfig.playground === true && graphql.apolloConfig.introspection === false (playground accessible in all cases, introspection disabled) +// export default config({ +// db: { +// provider: 'sqlite', +// url: process.env.DATABASE_URL || 'file:./keystone-example.db', +// }, +// lists, +// graphql: { +// apolloConfig: { +// playground: true, +// introspection: false, +// }, +// }, // }); -// graphql.apolloConfig.playground === { settings: ... } (playground accessible in all cases with further customisation - https://www.apollographql.com/docs/apollo-server/testing/graphql-playground) +// graphql.apolloConfig.playground === { settings: ... } (playground accessible in all cases with further customisation - https://www.apollographql.com/docs/apollo-server/testing/graphql-playground, introspection will be enabled by default) // export default config({ // db: { // provider: 'sqlite', @@ -47,7 +62,7 @@ import { lists } from './schema'; // } // }); -// process.env.NODE_ENV === 'production' (playground not accessible in production) +// process.env.NODE_ENV === 'production' (playground not accessible in production, introspection will be disabled by default) // process.env.NODE_ENV = 'production'; // export default config({ // db: { @@ -62,7 +77,7 @@ import { lists } from './schema'; // } // }); -// not specified at all (playground uses defaults) +// not specified at all (playground and introspection uses defaults, enabled in development and disabled in production) export default config({ db: { provider: 'sqlite', diff --git a/examples-staging/playground/package.json b/examples-staging/playground/package.json index b9720b7c057..7ea2c4206f9 100644 --- a/examples-staging/playground/package.json +++ b/examples-staging/playground/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-playground", - "version": "1.0.5", + "version": "1.0.6", "private": true, "license": "MIT", "scripts": { @@ -9,11 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": ">=v12.13.1" diff --git a/examples-staging/playground/schema.graphql b/examples-staging/playground/schema.graphql index 67148d43a55..fe4aba7b55f 100644 --- a/examples-staging/playground/schema.graphql +++ b/examples-staging/playground/schema.graphql @@ -1,14 +1,20 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Note { id: ID! label: String } +input NoteWhereUniqueInput { + id: ID +} + input NoteWhereInput { AND: [NoteWhereInput!] OR: [NoteWhereInput!] NOT: [NoteWhereInput!] id: IDFilter - label: StringNullableFilter } input IDFilter { @@ -22,41 +28,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NoteWhereUniqueInput { - id: ID -} - input NoteOrderByInput { id: OrderDirection - label: OrderDirection } enum OrderDirection { @@ -140,6 +113,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/playground/schema.prisma b/examples-staging/playground/schema.prisma index 67c012abd3d..680ff9ec79d 100644 --- a/examples-staging/playground/schema.prisma +++ b/examples-staging/playground/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/playground/schema.ts b/examples-staging/playground/schema.ts index 592421080d2..89ec9cfac3a 100644 --- a/examples-staging/playground/schema.ts +++ b/examples-staging/playground/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { text } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Note: list({ diff --git a/examples-staging/roles/CHANGELOG.md b/examples-staging/roles/CHANGELOG.md index 25431826da1..6b3f0bd7e6d 100644 --- a/examples-staging/roles/CHANGELOG.md +++ b/examples-staging/roles/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-roles +## 4.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + ## 4.0.6 ### Patch Changes diff --git a/examples-staging/roles/keystone.ts b/examples-staging/roles/keystone.ts index 00436cb7796..03f620ef5ac 100644 --- a/examples-staging/roles/keystone.ts +++ b/examples-staging/roles/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import { lists } from './schema'; diff --git a/examples-staging/roles/package.json b/examples-staging/roles/package.json index 7734e122ecf..ecd8c71c289 100644 --- a/examples-staging/roles/package.json +++ b/examples-staging/roles/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-roles", - "version": "4.0.6", + "version": "4.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,16 +9,14 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/auth": "^31.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "next": "^10.2.3", + "@keystone-next/auth": "^32.0.0", + "@keystone-next/keystone": "^25.0.0", + "next": "^11.1.0", "react": "^17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/roles/schema.graphql b/examples-staging/roles/schema.graphql index ba8201c3db0..d3d71b849e7 100644 --- a/examples-staging/roles/schema.graphql +++ b/examples-staging/roles/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + input CreateInitialPersonInput { name: String email: String @@ -65,15 +68,15 @@ type Todo { assignedTo: Person } +input TodoWhereUniqueInput { + id: ID +} + input TodoWhereInput { AND: [TodoWhereInput!] OR: [TodoWhereInput!] NOT: [TodoWhereInput!] id: IDFilter - label: StringNullableFilter - isComplete: BooleanNullableFilter - isPrivate: BooleanNullableFilter - assignedTo: PersonWhereInput } input IDFilter { @@ -87,48 +90,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input BooleanNullableFilter { - equals: Boolean - not: BooleanNullableFilter -} - -input TodoWhereUniqueInput { - id: ID -} - input TodoOrderByInput { id: OrderDirection - label: OrderDirection - isComplete: OrderDirection - isPrivate: OrderDirection } enum OrderDirection { @@ -185,37 +148,49 @@ type PasswordState { isSet: Boolean! } +input PersonWhereUniqueInput { + id: ID + email: String +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] NOT: [PersonWhereInput!] id: IDFilter - name: StringNullableFilter email: StringNullableFilter - password: PasswordFilter - role: RoleWhereInput - tasks: TodoManyRelationFilter -} - -input PasswordFilter { - isSet: Boolean! } -input TodoManyRelationFilter { - every: TodoWhereInput - some: TodoWhereInput - none: TodoWhereInput +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } -input PersonWhereUniqueInput { - id: ID - email: String +input NestedStringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringNullableFilter } input PersonOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input PersonUpdateInput { @@ -280,40 +255,19 @@ type Role { assignedToCount(where: PersonWhereInput! = {}): Int } +input RoleWhereUniqueInput { + id: ID +} + input RoleWhereInput { AND: [RoleWhereInput!] OR: [RoleWhereInput!] NOT: [RoleWhereInput!] id: IDFilter - name: StringNullableFilter - canCreateTodos: BooleanNullableFilter - canManageAllTodos: BooleanNullableFilter - canSeeOtherPeople: BooleanNullableFilter - canEditOtherPeople: BooleanNullableFilter - canManagePeople: BooleanNullableFilter - canManageRoles: BooleanNullableFilter - assignedTo: PersonManyRelationFilter -} - -input PersonManyRelationFilter { - every: PersonWhereInput - some: PersonWhereInput - none: PersonWhereInput -} - -input RoleWhereUniqueInput { - id: ID } input RoleOrderByInput { id: OrderDirection - name: OrderDirection - canCreateTodos: OrderDirection - canManageAllTodos: OrderDirection - canSeeOtherPeople: OrderDirection - canEditOtherPeople: OrderDirection - canManagePeople: OrderDirection - canManageRoles: OrderDirection } input RoleUpdateInput { @@ -426,6 +380,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/roles/schema.prisma b/examples-staging/roles/schema.prisma index cf5f2e67c2d..e23b4b60055 100644 --- a/examples-staging/roles/schema.prisma +++ b/examples-staging/roles/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/roles/schema.ts b/examples-staging/roles/schema.ts index fcb7d1ec8de..fcf330ea0f0 100644 --- a/examples-staging/roles/schema.ts +++ b/examples-staging/roles/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, password, relationship, text } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, password, relationship, text } from '@keystone-next/keystone/fields'; import { isSignedIn, permissions, rules } from './access'; @@ -31,10 +31,14 @@ export const lists = createSchema({ - [ ] Extend the Admin UI to stop people creating private Todos assigned to someone else */ access: { - create: permissions.canCreateTodos, - read: rules.canReadTodos, - update: rules.canManageTodos, - delete: rules.canManageTodos, + operation: { + create: permissions.canCreateTodos, + }, + filter: { + query: rules.canReadTodos, + update: rules.canManageTodos, + delete: rules.canManageTodos, + }, }, ui: { hideCreate: args => !permissions.canCreateTodos(args), @@ -79,10 +83,14 @@ export const lists = createSchema({ - [x] Restrict tasks based on same item or canManageTodos */ access: { - create: permissions.canManagePeople, - read: rules.canReadPeople, - update: rules.canUpdatePeople, - delete: permissions.canManagePeople, + operation: { + create: permissions.canManagePeople, + delete: permissions.canManagePeople, + }, + filter: { + query: rules.canReadPeople, + update: rules.canUpdatePeople, + }, }, ui: { hideCreate: args => !permissions.canManagePeople(args), @@ -105,7 +113,7 @@ export const lists = createSchema({ /* The name of the user */ name: text({ isRequired: true }), /* The email of the user, used to sign in */ - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), /* The password of the user */ password: password({ isRequired: true, @@ -163,10 +171,12 @@ export const lists = createSchema({ - [ ] Extend the Admin UI with client-side validation based on the same set of rules */ access: { - create: permissions.canManageRoles, - read: isSignedIn, - update: permissions.canManageRoles, - delete: permissions.canManageRoles, + operation: { + create: permissions.canManageRoles, + query: isSignedIn, + update: permissions.canManageRoles, + delete: permissions.canManageRoles, + }, }, ui: { hideCreate: args => !permissions.canManageRoles(args), diff --git a/examples-staging/sandbox/CHANGELOG.md b/examples-staging/sandbox/CHANGELOG.md index e4c02593c4f..5c39b495b2b 100644 --- a/examples-staging/sandbox/CHANGELOG.md +++ b/examples-staging/sandbox/CHANGELOG.md @@ -1,5 +1,13 @@ # @keystone-next/example-sandbox +## 3.0.7 + +### Patch Changes + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + ## 3.0.6 ### Patch Changes diff --git a/examples-staging/sandbox/keystone.ts b/examples-staging/sandbox/keystone.ts index 41ccd6484aa..0190f06f808 100644 --- a/examples-staging/sandbox/keystone.ts +++ b/examples-staging/sandbox/keystone.ts @@ -3,7 +3,7 @@ // we're currently essentially using CodeSandbox CI as a way to get // published packages that we can try out in projects that aren't in the repo -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples-staging/sandbox/package.json b/examples-staging/sandbox/package.json index 23899c25be7..9ab8de93064 100644 --- a/examples-staging/sandbox/package.json +++ b/examples-staging/sandbox/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-sandbox", - "version": "3.0.6", + "version": "3.0.7", "private": true, "license": "MIT", "scripts": { @@ -8,9 +8,8 @@ "sandbox": "yarn && yarn dev" }, "dependencies": { - "@keystone-next/auth": "^31.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/auth": "^32.0.0", + "@keystone-next/keystone": "^25.0.0" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/sandbox/schema.graphql b/examples-staging/sandbox/schema.graphql index 265367bfa79..1b415c31622 100644 --- a/examples-staging/sandbox/schema.graphql +++ b/examples-staging/sandbox/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Todo { id: ID! label: String @@ -8,17 +11,15 @@ type Todo { updatedAt: String } +input TodoWhereUniqueInput { + id: ID +} + input TodoWhereInput { AND: [TodoWhereInput!] OR: [TodoWhereInput!] NOT: [TodoWhereInput!] id: IDFilter - label: StringNullableFilter - isComplete: BooleanNullableFilter - assignedTo: UserWhereInput - finishBy: DateTimeNullableFilter - createdAt: DateTimeNullableFilter - updatedAt: DateTimeNullableFilter } input IDFilter { @@ -32,61 +33,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input BooleanNullableFilter { - equals: Boolean - not: BooleanNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input TodoWhereUniqueInput { - id: ID -} - input TodoOrderByInput { id: OrderDirection - label: OrderDirection - isComplete: OrderDirection - finishBy: OrderDirection - createdAt: OrderDirection - updatedAt: OrderDirection } enum OrderDirection { @@ -99,6 +47,8 @@ input TodoUpdateInput { isComplete: Boolean assignedTo: UserRelateToOneForUpdateInput finishBy: String + createdAt: String + updatedAt: String } input UserRelateToOneForUpdateInput { @@ -117,6 +67,8 @@ input TodoCreateInput { isComplete: Boolean assignedTo: UserRelateToOneForCreateInput finishBy: String + createdAt: String + updatedAt: String } input UserRelateToOneForCreateInput { @@ -144,39 +96,19 @@ type PasswordState { isSet: Boolean! } +input UserWhereUniqueInput { + id: ID +} + input UserWhereInput { AND: [UserWhereInput!] OR: [UserWhereInput!] NOT: [UserWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - password: PasswordFilter - tasks: TodoManyRelationFilter - createdAt: DateTimeNullableFilter - updatedAt: DateTimeNullableFilter -} - -input PasswordFilter { - isSet: Boolean! -} - -input TodoManyRelationFilter { - every: TodoWhereInput - some: TodoWhereInput - none: TodoWhereInput -} - -input UserWhereUniqueInput { - id: ID } input UserOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection - createdAt: OrderDirection - updatedAt: OrderDirection } input UserUpdateInput { @@ -184,6 +116,8 @@ input UserUpdateInput { email: String password: String tasks: TodoRelateToManyForUpdateInput + createdAt: String + updatedAt: String } input TodoRelateToManyForUpdateInput { @@ -203,6 +137,8 @@ input UserCreateInput { email: String password: String tasks: TodoRelateToManyForCreateInput + createdAt: String + updatedAt: String } input TodoRelateToManyForCreateInput { @@ -287,6 +223,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples-staging/sandbox/schema.prisma b/examples-staging/sandbox/schema.prisma index bd89ef81e54..8d49455e864 100644 --- a/examples-staging/sandbox/schema.prisma +++ b/examples-staging/sandbox/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples-staging/sandbox/schema.ts b/examples-staging/sandbox/schema.ts index f590920ff40..9951884f46d 100644 --- a/examples-staging/sandbox/schema.ts +++ b/examples-staging/sandbox/schema.ts @@ -1,10 +1,10 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, password, relationship, text, timestamp } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, password, relationship, text, timestamp } from '@keystone-next/keystone/fields'; // this implementation for createdBy and updatedBy is currently wrong so they're disabled for now const trackingFields = { createdAt: timestamp({ - access: { create: false, read: true, update: false }, + access: { read: () => true, create: () => false, update: () => false }, defaultValue: () => new Date().toISOString(), ui: { createView: { fieldMode: 'hidden' }, @@ -22,7 +22,7 @@ const trackingFields = { // }, // }), updatedAt: timestamp({ - access: { create: false, read: true, update: false }, + access: { read: () => true, create: () => false, update: () => false }, hooks: { resolveInput: () => new Date().toISOString(), }, diff --git a/examples/README.md b/examples/README.md index e83361784cb..0e8cca9c196 100644 --- a/examples/README.md +++ b/examples/README.md @@ -23,7 +23,7 @@ Each project below demonstrates a Keystone feature you can learn about and exper - [`extendGraphqlSchema`](./extend-graphql-schema): Extends the GraphQL API of the Task Manager base. - [Virtual field](./virtual-field): Adds virtual fields to the Blog base. - [Document field](./document-field): Adds document fields to the Blog base. -- [Testing](./testing): Adds tests with `@keystone-next/testing` to the `withAuth()` example. +- [Testing](./testing): Adds tests with `@keystone-next/keystone/testing` to the `withAuth()` example. - [Custom field](./custom-field): Adds a custom `stars` field to the Blog base. - [Custom field view](./custom-field-view): Adds a custom Admin UI view to a `json` field to the Task Manager base. - [Custom Admin UI logo](./custom-admin-ui-logo): Adds a custom logo in the Admin UI to the Task Manager base. diff --git a/examples/blog/CHANGELOG.md b/examples/blog/CHANGELOG.md index d15f710f338..6c22ba29be7 100644 --- a/examples/blog/CHANGELOG.md +++ b/examples/blog/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-next/example-blog +## 2.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +* [#6370](https://github.com/keystonejs/keystone/pull/6370) [`9d8ae78ff`](https://github.com/keystonejs/keystone/commit/9d8ae78ffacbff7f2e41a8ec5ba2ca7cf320834a) Thanks [@bladey](https://github.com/bladey)! - Adds ability to seed data for `blog` and `task-manager` examples. Use `yarn seed-data` in either examples folder to create a set of example data. + +* Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 2.0.6 ### Patch Changes diff --git a/examples/blog/README.md b/examples/blog/README.md index 4f70b318e2f..5bc8b3be47f 100644 --- a/examples/blog/README.md +++ b/examples/blog/README.md @@ -2,29 +2,33 @@ This project implements a basic **Blog**, with `Posts` and `Authors`. -You can use it as a starting place for learning how to use Keystone. +Use it as a starting place for learning how to use Keystone. ## Instructions -To run this project, clone the Keystone repository locally then navigate to this directory and run: +To run this project: -```shell -yarn dev -``` +1. Clone the Keystone repository locally +2. Navigate to this directory `cd examples/blog` +3. Run `yarn dev` This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. -🚀 Congratulations, you're now up and running with Keystone! +Congratulations, you're now up and running with Keystone! 🚀 -## Next steps +### Optional: add sample data + +This example includes sample data. To add it to your database: -This project is bare bones, and doesn't use any of Keystone's advanced features. -We encourage you to experiment with the code here to see how Keystone works, become familiar with the Admin UI, and learn about the GraphQL Playground. +1. Ensure you’ve initialised your project with `yarn dev` at least once. +2. Run `yarn seed-data`. This will populate your database with sample content. +3. Run `yarn dev` again to startup Admin UI with sample data in place. + +## Next steps -Once you've got the hang of using this project, you can check out the [feature examples](../). -These projects build on this starter project and show you how to use Keystones advanced features to take your project to the next level. +Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the GraphQL Playground. -When you've got the hang of the Blog app, try a [feature project](../) to learn Keystone's advanced features and take your knowledge to the next level. +When you’ve got the hang of this base project, try a [feature project](../) to learn Keystone’s advanced features and take your knowledge to the next level. diff --git a/examples/blog/keystone.ts b/examples/blog/keystone.ts index e961168f85e..89001a1390f 100644 --- a/examples/blog/keystone.ts +++ b/examples/blog/keystone.ts @@ -1,10 +1,16 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; +import { insertSeedData } from './seed-data'; export default config({ db: { provider: 'sqlite', url: process.env.DATABASE_URL || 'file:./keystone-example.db', + async onConnect(context) { + if (process.argv.includes('--seed-data')) { + await insertSeedData(context); + } + }, }, lists, }); diff --git a/examples/blog/package.json b/examples/blog/package.json index d9bac9e7a8d..14b39a0db65 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -1,19 +1,19 @@ { "name": "@keystone-next/example-blog", - "version": "2.0.6", + "version": "2.0.7", "private": true, "license": "MIT", "scripts": { "dev": "keystone-next dev", "start": "keystone-next start", - "build": "keystone-next build" + "build": "keystone-next build", + "seed-data": "keystone-next --seed-data" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/blog/schema.graphql b/examples/blog/schema.graphql index 1dd72c9481f..d0edfca215f 100644 --- a/examples/blog/schema.graphql +++ b/examples/blog/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -12,16 +15,16 @@ enum PostStatusType { published } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter title: StringNullableFilter - status: PostStatusTypeNullableFilter - content: StringNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -63,34 +66,8 @@ input NestedStringNullableFilter { not: NestedStringNullableFilter } -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - content: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -143,31 +120,19 @@ type Author { postsCount(where: PostWhereInput! = {}): Int } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -276,6 +241,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/blog/schema.prisma b/examples/blog/schema.prisma index ba6c0a653db..33d6cc1f737 100644 --- a/examples/blog/schema.prisma +++ b/examples/blog/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/blog/schema.ts b/examples/blog/schema.ts index 0293cce7eb0..62895796062 100644 --- a/examples/blog/schema.ts +++ b/examples/blog/schema.ts @@ -1,10 +1,10 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Post: list({ fields: { - title: text({ isRequired: true }), + title: text({ isRequired: true, isFilterable: true }), status: select({ dataType: 'enum', options: [ @@ -20,7 +20,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), }, }), diff --git a/examples/blog/seed-data/data.ts b/examples/blog/seed-data/data.ts new file mode 100644 index 00000000000..1060fda1276 --- /dev/null +++ b/examples/blog/seed-data/data.ts @@ -0,0 +1,77 @@ +export const authors = [ + { name: 'Arthur Conan Doyle', email: 'arthur.cd@email.com' }, + { name: 'Emily Brontë', email: 'emily.b@email.com' }, + { name: 'Jane Austen', email: 'austen.j@email.com' }, + { name: 'Daren Shipley', email: 'austen.j@email.com' }, + { name: 'Lewis Carroll', email: 'lewis.carroll@email.com' }, + { name: 'Lewis Carroll', email: 'lewis.carroll@email.com' }, + { name: 'George Eliot', email: 'g.eliot@email.com' }, + { name: 'L. Frank Baum', email: 'l.baum@email.com' }, +]; + +export const posts = [ + { + title: 'The Adventures of Sherlock Holmes', + status: 'draft', + publishDate: '2021-08-19T02:30:00.000Z', + author: 'Arthur Conan Doyle', + content: + 'One night—it was on the twentieth of March, 1888—I was returning from a journey to a patient (for I had now returned to civil practice), when my way led me through Baker Street. As I passed the well-remembered door, which must always be associated in my mind with my wooing, and with the dark incidents of the Study in Scarlet, I was seized with a keen desire to see Holmes again, and to know how he was employing his extraordinary powers. His rooms were brilliantly lit, and, even as I looked up, I saw his tall, spare figure pass twice in a dark silhouette against the blind. He was pacing the room swiftly, eagerly, with his head sunk upon his chest and his hands clasped behind him. To me, who knew his every mood and habit, his attitude and manner told their own story. He was at work again. He had risen out of his drug-created dreams and was hot upon the scent of some new problem. I rang the bell and was shown up to the chamber which had formerly been in part my own. ', + }, + { + title: 'Wuthering Heights', + status: 'published', + publishDate: '2021-04-22T05:43:51.000Z', + author: 'Emily Brontë', + content: + 'I have just returned from a visit to my landlord—the solitary neighbour that I shall be troubled with. This is certainly a beautiful country! In all England, I do not believe that I could have fixed on a situation so completely removed from the stir of society. A perfect misanthropist’s Heaven—and Mr. Heathcliff and I are such a suitable pair to divide the desolation between us. A capital fellow! He little imagined how my heart warmed towards him when I beheld his black eyes withdraw so suspiciously under their brows, as I rode up, and when his fingers sheltered themselves, with a jealous resolution, still further in his waistcoat, as I announced my name.', + }, + { + title: 'Emma', + status: 'draft', + publishDate: '2021-02-02T20:02:37.000Z', + author: 'Jane Austen', + content: + 'Emma Woodhouse, handsome, clever, and rich, with a comfortable home and happy disposition, seemed to unite some of the best blessings of existence; and had lived nearly twenty-one years in the world with very little to distress or vex her. She was the youngest of the two daughters of a most affectionate, indulgent father; and had, in consequence of her sister’s marriage, been mistress of his house from a very early period. Her mother had died too long ago for her to have more than an indistinct remembrance of her caresses; and her place had been supplied by an excellent woman as governess, who had fallen little short of a mother in affection.', + }, + { + title: 'Sense and Sensibility', + status: 'published', + publishDate: '2021-05-07T22:17:07.000Z', + author: 'Jane Austen', + content: + 'The family of Dashwood had long been settled in Sussex. Their estate was large, and their residence was at Norland Park, in the centre of their property, where, for many generations, they had lived in so respectable a manner as to engage the general good opinion of their surrounding acquaintance. The late owner of this estate was a single man, who lived to a very advanced age, and who for many years of his life, had a constant companion and housekeeper in his sister. But her death, which happened ten years before his own, produced a great alteration in his home; for to supply her loss, he invited and received into his house the family of his nephew Mr. Henry Dashwood, the legal inheritor of the Norland estate, and the person to whom he intended to bequeath it. In the society of his nephew and niece, and their children, the old Gentleman’s days were comfortably spent. His attachment to them all increased. The constant attention of Mr. and Mrs. Henry Dashwood to his wishes, which proceeded not merely from interest, but from goodness of heart, gave him every degree of solid comfort which his age could receive; and the cheerfulness of the children added a relish to his existence.', + }, + { + title: 'Through the Looking-Glass', + status: 'draft', + publishDate: '2021-03-09T05:41:37.000Z', + author: 'Lewis Carroll', + content: + 'One thing was certain, that the white kitten had had nothing to do with it: it was the black kitten’s fault entirely. For the white kitten had been having its face washed by the old cat for the last quarter of an hour (and bearing it pretty well, considering); so you see that it couldn’t have had any hand in the mischief. ', + }, + { + title: 'Jabberwocky', + status: 'published', + publishDate: '2021-07-27T00:12:02.000Z', + author: 'Lewis Carroll', + content: + '"’Twas brillig, and the slithy toves Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe. “Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!”" ', + }, + { + title: 'Middlemarch', + status: 'draft', + publishDate: '2021-08-07T05:50:57.000Z', + author: 'George Eliot', + content: + 'Who that cares much to know the history of man, and how the mysterious mixture behaves under the varying experiments of Time, has not dwelt, at least briefly, on the life of Saint Theresa, has not smiled with some gentleness at the thought of the little girl walking forth one morning hand-in-hand with her still smaller brother, to go and seek martyrdom in the country of the Moors? Out they toddled from rugged Avila, wide-eyed and helpless-looking as two fawns, but with human hearts, already beating to a national idea; until domestic reality met them in the shape of uncles, and turned them back from their great resolve. That child-pilgrimage was a fit beginning. Theresa’s passionate, ideal nature demanded an epic life: what were many-volumed romances of chivalry and the social conquests of a brilliant girl to her? Her flame quickly burned up that light fuel; and, fed from within, soared after some illimitable satisfaction, some object which would never justify weariness, which would reconcile self-despair with the rapturous consciousness of life beyond self. She found her epos in the reform of a religious order. ', + }, + { + title: 'The Wonderful Wizard of Oz', + status: 'published', + publishDate: '2021-03-01T06:41:57.000Z', + author: 'L. Frank Baum', + content: + 'Dorothy lived in the midst of the great Kansas prairies, with Uncle Henry, who was a farmer, and Aunt Em, who was the farmer’s wife. Their house was small, for the lumber to build it had to be carried by wagon many miles. There were four walls, a floor and a roof, which made one room; and this room contained a rusty looking cookstove, a cupboard for the dishes, a table, three or four chairs, and the beds. Uncle Henry and Aunt Em had a big bed in one corner, and Dorothy a little bed in another corner. There was no garret at all, and no cellar—except a small hole dug in the ground, called a cyclone cellar, where the family could go in case one of those great whirlwinds arose, mighty enough to crush any building in its path. It was reached by a trap door in the middle of the floor, from which a ladder led down into the small, dark hole.', + }, +]; diff --git a/examples/blog/seed-data/index.ts b/examples/blog/seed-data/index.ts new file mode 100644 index 00000000000..8232192c632 --- /dev/null +++ b/examples/blog/seed-data/index.ts @@ -0,0 +1,67 @@ +import { KeystoneContext } from '@keystone-next/keystone/types'; +import { authors, posts } from './data'; + +type AuthorProps = { + name: string; + email: string; +}; + +type PostProps = { + title: string; + status: string; + publishDate: string; + author: Object; + content: string; +}; + +export async function insertSeedData(context: KeystoneContext) { + console.log(`🌱 Inserting seed data`); + + const createAuthor = async (authorData: AuthorProps) => { + let author = null; + try { + author = await context.lists.Author.findOne({ + where: { email: authorData.email }, + query: 'id', + }); + } catch (e) {} + if (!author) { + author = await context.lists.Author.createOne({ + data: authorData, + query: 'id', + }); + } + return author; + }; + + const createPost = async (postData: PostProps) => { + let authors; + try { + authors = await context.lists.Author.findMany({ + where: { name: { equals: postData.author } }, + query: 'id', + }); + } catch (e) { + authors = []; + } + postData.author = { connect: { id: authors[0].id } }; + const post = await context.lists.Post.createOne({ + data: postData, + query: 'id', + }); + return post; + }; + + for (const author of authors) { + console.log(`👩 Adding author: ${author.name}`); + await createAuthor(author); + } + for (const post of posts) { + console.log(`📝 Adding post: ${post.title}`); + await createPost(post); + } + + console.log(`✅ Seed data inserted`); + console.log(`👋 Please start the process with \`yarn dev\` or \`npm run dev\``); + process.exit(); +} diff --git a/examples/custom-admin-ui-logo/CHANGELOG.md b/examples/custom-admin-ui-logo/CHANGELOG.md index 000593008f5..9bf39544be5 100644 --- a/examples/custom-admin-ui-logo/CHANGELOG.md +++ b/examples/custom-admin-ui-logo/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-custom-admin-ui-logo +## 1.0.2 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/core@3.2.0 + ## 1.0.1 ### Patch Changes diff --git a/examples/custom-admin-ui-logo/admin/components/CustomLogo.tsx b/examples/custom-admin-ui-logo/admin/components/CustomLogo.tsx index f6f1c75017d..49877093cdc 100644 --- a/examples/custom-admin-ui-logo/admin/components/CustomLogo.tsx +++ b/examples/custom-admin-ui-logo/admin/components/CustomLogo.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import Link from 'next/link'; import { jsx, H3 } from '@keystone-ui/core'; diff --git a/examples/custom-admin-ui-logo/admin/config.tsx b/examples/custom-admin-ui-logo/admin/config.tsx index d5e845d1013..58dd45b55c6 100644 --- a/examples/custom-admin-ui-logo/admin/config.tsx +++ b/examples/custom-admin-ui-logo/admin/config.tsx @@ -1,4 +1,4 @@ -import { AdminConfig } from '@keystone-next/types'; +import { AdminConfig } from '@keystone-next/keystone/types'; import { CustomLogo } from './components/CustomLogo'; // Presently the Logo is the only Admin UI component that is customisable. diff --git a/examples/custom-admin-ui-logo/keystone.ts b/examples/custom-admin-ui-logo/keystone.ts index a74fdce21b4..982bbe47545 100644 --- a/examples/custom-admin-ui-logo/keystone.ts +++ b/examples/custom-admin-ui-logo/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/custom-admin-ui-logo/package.json b/examples/custom-admin-ui-logo/package.json index 376a249bed9..563c72c024b 100644 --- a/examples/custom-admin-ui-logo/package.json +++ b/examples/custom-admin-ui-logo/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-admin-ui-logo", - "version": "1.0.1", + "version": "1.0.2", "private": true, "license": "MIT", "scripts": { @@ -9,15 +9,13 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/core": "^3.1.0", - "next": "^10.2.3", + "@keystone-next/keystone": "^25.0.0", + "@keystone-ui/core": "^3.2.0", + "next": "^11.1.0", "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-admin-ui-logo/schema.graphql b/examples/custom-admin-ui-logo/schema.graphql index e194b7cb406..24200845cd6 100644 --- a/examples/custom-admin-ui-logo/schema.graphql +++ b/examples/custom-admin-ui-logo/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Task { id: ID! label: String @@ -13,6 +16,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -87,10 +94,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -148,6 +151,10 @@ type Person { tasksCount(where: TaskWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -163,10 +170,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -276,6 +279,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/custom-admin-ui-logo/schema.prisma b/examples/custom-admin-ui-logo/schema.prisma index a1efaced2f7..78461ee962d 100644 --- a/examples/custom-admin-ui-logo/schema.prisma +++ b/examples/custom-admin-ui-logo/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/custom-admin-ui-logo/schema.ts b/examples/custom-admin-ui-logo/schema.ts index 9b539803be8..d76a4cb034d 100644 --- a/examples/custom-admin-ui-logo/schema.ts +++ b/examples/custom-admin-ui-logo/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -18,11 +18,15 @@ export const lists = createSchema({ assignedTo: relationship({ ref: 'Person.tasks', many: false }), finishBy: timestamp(), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/custom-admin-ui-navigation/CHANGELOG.md b/examples/custom-admin-ui-navigation/CHANGELOG.md index a9d48b60e5a..ddc12ffaded 100644 --- a/examples/custom-admin-ui-navigation/CHANGELOG.md +++ b/examples/custom-admin-ui-navigation/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-custom-navigation-component +## 5.0.1 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 5.0.0 ### Major Changes diff --git a/examples/custom-admin-ui-navigation/README.md b/examples/custom-admin-ui-navigation/README.md index 486add508b1..8fc2df99a31 100644 --- a/examples/custom-admin-ui-navigation/README.md +++ b/examples/custom-admin-ui-navigation/README.md @@ -39,7 +39,7 @@ The exported components object is expected to have the following type signature: Keystone conveniently exports an AdminConfig type for DX. ```typescript -import { AdminConfig } from '@keystone-next/types'; +import { AdminConfig } from '@keystone-next/keystone/types'; export const components: AdminConfig['components'] = { Logo, Navigation, diff --git a/examples/custom-admin-ui-navigation/admin/config.ts b/examples/custom-admin-ui-navigation/admin/config.ts index 4e65a6cec7d..7902ad3ba41 100644 --- a/examples/custom-admin-ui-navigation/admin/config.ts +++ b/examples/custom-admin-ui-navigation/admin/config.ts @@ -1,4 +1,4 @@ -import { AdminConfig } from '@keystone-next/types'; +import { AdminConfig } from '@keystone-next/keystone/types'; import { CustomNavigation } from './components/CustomNavigation'; export const components: AdminConfig['components'] = { diff --git a/examples/custom-admin-ui-navigation/keystone.ts b/examples/custom-admin-ui-navigation/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/custom-admin-ui-navigation/keystone.ts +++ b/examples/custom-admin-ui-navigation/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/custom-admin-ui-navigation/package.json b/examples/custom-admin-ui-navigation/package.json index 461c3c0d424..86c3496dd8e 100644 --- a/examples/custom-admin-ui-navigation/package.json +++ b/examples/custom-admin-ui-navigation/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-admin-ui-navigation", - "version": "5.0.0", + "version": "5.0.1", "private": true, "license": "MIT", "scripts": { @@ -9,13 +9,11 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", + "@keystone-next/keystone": "^25.0.0", "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-admin-ui-navigation/schema.graphql b/examples/custom-admin-ui-navigation/schema.graphql index e194b7cb406..24200845cd6 100644 --- a/examples/custom-admin-ui-navigation/schema.graphql +++ b/examples/custom-admin-ui-navigation/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Task { id: ID! label: String @@ -13,6 +16,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -87,10 +94,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -148,6 +151,10 @@ type Person { tasksCount(where: TaskWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -163,10 +170,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -276,6 +279,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/custom-admin-ui-navigation/schema.prisma b/examples/custom-admin-ui-navigation/schema.prisma index a1efaced2f7..78461ee962d 100644 --- a/examples/custom-admin-ui-navigation/schema.prisma +++ b/examples/custom-admin-ui-navigation/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/custom-admin-ui-navigation/schema.ts b/examples/custom-admin-ui-navigation/schema.ts index 9b539803be8..d76a4cb034d 100644 --- a/examples/custom-admin-ui-navigation/schema.ts +++ b/examples/custom-admin-ui-navigation/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -18,11 +18,15 @@ export const lists = createSchema({ assignedTo: relationship({ ref: 'Person.tasks', many: false }), finishBy: timestamp(), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/custom-admin-ui-pages/CHANGELOG.md b/examples/custom-admin-ui-pages/CHANGELOG.md index 68e1f42b5a0..e25458cbf78 100644 --- a/examples/custom-admin-ui-pages/CHANGELOG.md +++ b/examples/custom-admin-ui-pages/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-custom-admin-ui-pages +## 1.0.1 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/core@3.2.0 + ## 1.0.0 ### Major Changes diff --git a/examples/custom-admin-ui-pages/admin/config.ts b/examples/custom-admin-ui-pages/admin/config.ts index 12e80c22bb2..ec880712dea 100644 --- a/examples/custom-admin-ui-pages/admin/config.ts +++ b/examples/custom-admin-ui-pages/admin/config.ts @@ -1,4 +1,4 @@ -import type { AdminConfig } from '@keystone-next/types'; +import type { AdminConfig } from '@keystone-next/keystone/types'; import { CustomNavigation } from './components/CustomNavigation'; export const components: AdminConfig['components'] = { Navigation: CustomNavigation, diff --git a/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx b/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx index 4e14dbb36cf..bf4d9f7af54 100644 --- a/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx +++ b/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { PageContainer } from '@keystone-next/keystone/admin-ui/components'; import { jsx, Heading } from '@keystone-ui/core'; diff --git a/examples/custom-admin-ui-pages/keystone.ts b/examples/custom-admin-ui-pages/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/custom-admin-ui-pages/keystone.ts +++ b/examples/custom-admin-ui-pages/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/custom-admin-ui-pages/package.json b/examples/custom-admin-ui-pages/package.json index c89af45ea77..5dc75970641 100644 --- a/examples/custom-admin-ui-pages/package.json +++ b/examples/custom-admin-ui-pages/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-admin-ui-pages", - "version": "1.0.0", + "version": "1.0.1", "private": true, "license": "MIT", "scripts": { @@ -9,14 +9,12 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/core": "^3.1.0", + "@keystone-next/keystone": "^25.0.0", + "@keystone-ui/core": "^3.2.0", "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-admin-ui-pages/schema.graphql b/examples/custom-admin-ui-pages/schema.graphql index e194b7cb406..24200845cd6 100644 --- a/examples/custom-admin-ui-pages/schema.graphql +++ b/examples/custom-admin-ui-pages/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Task { id: ID! label: String @@ -13,6 +16,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -87,10 +94,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -148,6 +151,10 @@ type Person { tasksCount(where: TaskWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -163,10 +170,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -276,6 +279,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/custom-admin-ui-pages/schema.prisma b/examples/custom-admin-ui-pages/schema.prisma index a1efaced2f7..78461ee962d 100644 --- a/examples/custom-admin-ui-pages/schema.prisma +++ b/examples/custom-admin-ui-pages/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/custom-admin-ui-pages/schema.ts b/examples/custom-admin-ui-pages/schema.ts index 9b539803be8..d76a4cb034d 100644 --- a/examples/custom-admin-ui-pages/schema.ts +++ b/examples/custom-admin-ui-pages/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -18,11 +18,15 @@ export const lists = createSchema({ assignedTo: relationship({ ref: 'Person.tasks', many: false }), finishBy: timestamp(), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/custom-field-view/CHANGELOG.md b/examples/custom-field-view/CHANGELOG.md index 372a08a14be..fed313d70a9 100644 --- a/examples/custom-field-view/CHANGELOG.md +++ b/examples/custom-field-view/CHANGELOG.md @@ -1,5 +1,18 @@ # @keystone-next/example-custom-field-view +## 1.0.3 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/icons@4.0.1 + ## 1.0.2 ### Patch Changes diff --git a/examples/custom-field-view/fields/related-links/components.tsx b/examples/custom-field-view/fields/related-links/components.tsx index 9c94eaa4182..03d6bab221e 100644 --- a/examples/custom-field-view/fields/related-links/components.tsx +++ b/examples/custom-field-view/fields/related-links/components.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { FieldProps } from '@keystone-next/types'; +import { FieldProps } from '@keystone-next/keystone/types'; import { css } from '@emotion/css'; import { Button } from '@keystone-ui/button'; import { FieldContainer, FieldLabel, TextInput } from '@keystone-ui/fields'; import { MinusCircleIcon, EditIcon } from '@keystone-ui/icons'; -import { controller } from '@keystone-next/fields/types/json/views'; +import { controller } from '@keystone-next/keystone/fields/types/json/views'; import { Fragment, useState } from 'react'; interface RelatedLink { diff --git a/examples/custom-field-view/keystone.ts b/examples/custom-field-view/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/custom-field-view/keystone.ts +++ b/examples/custom-field-view/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/custom-field-view/package.json b/examples/custom-field-view/package.json index cdf9cf19396..1a28687a4fd 100644 --- a/examples/custom-field-view/package.json +++ b/examples/custom-field-view/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-field-view", - "version": "1.0.2", + "version": "1.0.3", "private": true, "license": "MIT", "scripts": { @@ -10,17 +10,15 @@ }, "dependencies": { "@emotion/css": "^11.1.3", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.2", - "@keystone-ui/icons": "^4.0.0", + "@keystone-next/keystone": "^25.0.0", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/icons": "^4.0.1", "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-field-view/schema.graphql b/examples/custom-field-view/schema.graphql index 8f3770570e0..124e26dd9dc 100644 --- a/examples/custom-field-view/schema.graphql +++ b/examples/custom-field-view/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Task { id: ID! label: String @@ -14,6 +17,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -88,10 +95,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -151,6 +154,10 @@ type Person { tasksCount(where: TaskWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -166,10 +173,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -279,6 +282,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/custom-field-view/schema.prisma b/examples/custom-field-view/schema.prisma index 215c393f801..f9d9dc0a7e6 100644 --- a/examples/custom-field-view/schema.prisma +++ b/examples/custom-field-view/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/custom-field-view/schema.ts b/examples/custom-field-view/schema.ts index 242aa18100e..241c9f22f28 100644 --- a/examples/custom-field-view/schema.ts +++ b/examples/custom-field-view/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; -import { json, select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { json, select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -27,11 +27,15 @@ export const lists = createSchema({ }, }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/custom-field/CHANGELOG.md b/examples/custom-field/CHANGELOG.md index 5e7867dc6a5..ab4324cef1d 100644 --- a/examples/custom-field/CHANGELOG.md +++ b/examples/custom-field/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-custom-field +## 0.0.4 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/fields@4.1.3 + ## 0.0.3 ### Patch Changes diff --git a/examples/custom-field/keystone.ts b/examples/custom-field/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/custom-field/keystone.ts +++ b/examples/custom-field/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/custom-field/package.json b/examples/custom-field/package.json index b8e4b695650..874ece11724 100644 --- a/examples/custom-field/package.json +++ b/examples/custom-field/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-custom-field", - "version": "0.0.3", + "version": "0.0.4", "private": true, "license": "MIT", "scripts": { @@ -9,14 +9,12 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/fields": "^4.1.2", + "@keystone-next/keystone": "^25.0.0", + "@keystone-ui/fields": "^4.1.3", "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-field/schema.graphql b/examples/custom-field/schema.graphql index 696dd83cc2f..f165d6d76c5 100644 --- a/examples/custom-field/schema.graphql +++ b/examples/custom-field/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -13,17 +16,15 @@ enum PostStatusType { published } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: PostStatusTypeNullableFilter - content: StringNullableFilter - rating: IntNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -37,74 +38,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input IntNullableFilter { - equals: Int - in: [Int!] - notIn: [Int!] - lt: Int - lte: Int - gt: Int - gte: Int - not: IntNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - content: OrderDirection - rating: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -159,31 +94,19 @@ type Author { postsCount(where: PostWhereInput! = {}): Int } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -292,6 +215,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/custom-field/schema.prisma b/examples/custom-field/schema.prisma index 4a70cebb4f4..4cc3e13970b 100644 --- a/examples/custom-field/schema.prisma +++ b/examples/custom-field/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/custom-field/schema.ts b/examples/custom-field/schema.ts index edb3ca3b4c0..594a821aa73 100644 --- a/examples/custom-field/schema.ts +++ b/examples/custom-field/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { stars } from './stars-field'; export const lists = createSchema({ @@ -22,7 +22,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), }, }), diff --git a/examples/custom-field/stars-field/index.ts b/examples/custom-field/stars-field/index.ts index 827ed5a137c..5a0fe722542 100644 --- a/examples/custom-field/stars-field/index.ts +++ b/examples/custom-field/stars-field/index.ts @@ -5,28 +5,26 @@ import { FieldTypeFunc, CommonFieldConfig, orderDirectionEnum, - schema, + graphql, filters, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; // this field is based on the integer field // but with validation to ensure the value is within an expected range // and a different input in the Admin UI -// https://github.com/keystonejs/keystone/tree/master/packages/fields/src/types/integer +// https://github.com/keystonejs/keystone/tree/master/packages/keystone/src/fields/types/integer export type StarsFieldConfig = CommonFieldConfig & { defaultValue?: FieldDefaultValue; isRequired?: boolean; - isUnique?: boolean; - isIndexed?: boolean; + isIndexed?: boolean | 'unique'; maxStars?: number; }; export const stars = ({ isIndexed, - isUnique, isRequired, defaultValue, maxStars = 5, @@ -38,7 +36,7 @@ export const stars = kind: 'scalar', mode: 'optional', scalar: 'Int', - index: getIndexType({ isIndexed, isUnique }), + index: isIndexed === true ? 'index' : isIndexed || undefined, })({ // this passes through all of the common configuration like access control and etc. ...config, @@ -57,11 +55,11 @@ export const stars = // all of these inputs are optional if they don't make sense for a particular field type input: { where: { - arg: schema.arg({ type: filters[meta.provider].Int.optional }), + arg: graphql.arg({ type: filters[meta.provider].Int.optional }), resolve: filters.resolveCommon, }, create: { - arg: schema.arg({ type: schema.Int }), + arg: graphql.arg({ type: graphql.Int }), // this field type doesn't need to do anything special // but field types can specify resolvers for inputs like they can for their output GraphQL field // this function can be omitted, it is here purely to show how you could change it @@ -82,12 +80,12 @@ export const stars = return val; }, }, - update: { arg: schema.arg({ type: schema.Int }) }, - orderBy: { arg: schema.arg({ type: orderDirectionEnum }) }, + update: { arg: graphql.arg({ type: graphql.Int }) }, + orderBy: { arg: graphql.arg({ type: orderDirectionEnum }) }, }, // this - output: schema.field({ - type: schema.Int, + output: graphql.field({ + type: graphql.Int, // like the input resolvers, providing the resolver is unnecessary if you're just returning the value // it is shown here to show what you could do // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -104,16 +102,3 @@ export const stars = defaultValue, }, }); - -function getIndexType({ - isIndexed, - isUnique, -}: { - isIndexed?: boolean; - isUnique?: boolean; -}): undefined | 'index' | 'unique' { - if (isUnique && isIndexed) { - throw new Error('Only one of isUnique and isIndexed can be passed to field types'); - } - return isIndexed ? 'index' : isUnique ? 'unique' : undefined; -} diff --git a/examples/custom-field/stars-field/views.tsx b/examples/custom-field/stars-field/views.tsx index c6672ed4183..13c28254668 100644 --- a/examples/custom-field/stars-field/views.tsx +++ b/examples/custom-field/stars-field/views.tsx @@ -8,7 +8,7 @@ import { FieldController, FieldControllerConfig, FieldProps, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; import { StarsInput } from './stars-input'; // this is the component shown in the create modal and item page diff --git a/examples/default-values/CHANGELOG.md b/examples/default-values/CHANGELOG.md index 40fe398fb9a..854f910a38f 100644 --- a/examples/default-values/CHANGELOG.md +++ b/examples/default-values/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-default-values +## 1.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 1.0.6 ### Patch Changes diff --git a/examples/default-values/keystone.ts b/examples/default-values/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/default-values/keystone.ts +++ b/examples/default-values/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/default-values/package.json b/examples/default-values/package.json index af3ba2e7b19..6e9eadc8e3b 100644 --- a/examples/default-values/package.json +++ b/examples/default-values/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-default-values", - "version": "1.0.6", + "version": "1.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,11 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/default-values/schema.graphql b/examples/default-values/schema.graphql index e194b7cb406..24200845cd6 100644 --- a/examples/default-values/schema.graphql +++ b/examples/default-values/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Task { id: ID! label: String @@ -13,6 +16,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -87,10 +94,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -148,6 +151,10 @@ type Person { tasksCount(where: TaskWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -163,10 +170,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -276,6 +279,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/default-values/schema.prisma b/examples/default-values/schema.prisma index a1efaced2f7..78461ee962d 100644 --- a/examples/default-values/schema.prisma +++ b/examples/default-values/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/default-values/schema.ts b/examples/default-values/schema.ts index 945e8f259f5..bb1e533e634 100644 --- a/examples/default-values/schema.ts +++ b/examples/default-values/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -44,11 +44,15 @@ export const lists = createSchema({ new Date(new Date().setUTCDate(new Date().getUTCDate() + 7)).toUTCString(), }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/document-field/CHANGELOG.md b/examples/document-field/CHANGELOG.md index 894c979f97a..592630a8e74 100644 --- a/examples/document-field/CHANGELOG.md +++ b/examples/document-field/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-document-field +## 1.1.3 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/fields-document@9.0.0 + ## 1.1.2 ### Patch Changes diff --git a/examples/document-field/keystone.ts b/examples/document-field/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/document-field/keystone.ts +++ b/examples/document-field/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/document-field/package.json b/examples/document-field/package.json index 03ffa30eeb0..9dc76bd34d7 100644 --- a/examples/document-field/package.json +++ b/examples/document-field/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-document-field", - "version": "1.1.2", + "version": "1.1.3", "private": true, "license": "MIT", "scripts": { @@ -11,15 +11,14 @@ }, "dependencies": { "@keystone-next/document-renderer": "^4.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/fields-document": "^8.0.0", - "@keystone-next/keystone": "^24.0.0", + "@keystone-next/fields-document": "^9.0.0", + "@keystone-next/keystone": "^25.0.0", "@preconstruct/next": "^3.0.0", - "next": "^10.2.3", + "next": "^11.1.0", "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/document-field/schema.graphql b/examples/document-field/schema.graphql index af2cccf7c54..6d7e7f7dc62 100644 --- a/examples/document-field/schema.graphql +++ b/examples/document-field/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -17,16 +20,15 @@ type Post_content_DocumentField { document(hydrateRelationships: Boolean! = false): JSON! } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - slug: StringNullableFilter - status: PostStatusTypeNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -40,63 +42,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID - slug: String -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - slug: OrderDirection - status: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -156,31 +103,19 @@ type Author_bio_DocumentField { document(hydrateRelationships: Boolean! = false): JSON! } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -291,6 +226,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/document-field/schema.prisma b/examples/document-field/schema.prisma index 001f50f5ef5..384462f9123 100644 --- a/examples/document-field/schema.prisma +++ b/examples/document-field/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/document-field/schema.ts b/examples/document-field/schema.ts index 8f16f399771..c28a69b16a4 100644 --- a/examples/document-field/schema.ts +++ b/examples/document-field/schema.ts @@ -1,12 +1,12 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { document } from '@keystone-next/fields-document'; export const lists = createSchema({ Post: list({ fields: { title: text({ isRequired: true }), - slug: text({ isRequired: true, isUnique: true }), + slug: text({ isRequired: true, isIndexed: 'unique' }), status: select({ dataType: 'enum', options: [ @@ -43,7 +43,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), bio: document({ // We want to constrain the formatting in Author bios to a limited set of options. diff --git a/examples/extend-graphql-schema/CHANGELOG.md b/examples/extend-graphql-schema/CHANGELOG.md index 0982ae9ed25..c21e00fa926 100644 --- a/examples/extend-graphql-schema/CHANGELOG.md +++ b/examples/extend-graphql-schema/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-extend-graphql-schema +## 1.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 1.0.6 ### Patch Changes diff --git a/examples/extend-graphql-schema/custom-schema.ts b/examples/extend-graphql-schema/custom-schema.ts index b29ddd7c49a..530a69ad696 100644 --- a/examples/extend-graphql-schema/custom-schema.ts +++ b/examples/extend-graphql-schema/custom-schema.ts @@ -1,4 +1,4 @@ -import { graphQLSchemaExtension } from '@keystone-next/keystone/schema'; +import { graphQLSchemaExtension } from '@keystone-next/keystone'; export const extendGraphqlSchema = graphQLSchemaExtension({ typeDefs: ` diff --git a/examples/extend-graphql-schema/keystone.ts b/examples/extend-graphql-schema/keystone.ts index e8c00e761f5..ed98d0d9b48 100644 --- a/examples/extend-graphql-schema/keystone.ts +++ b/examples/extend-graphql-schema/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; import { extendGraphqlSchema } from './custom-schema'; diff --git a/examples/extend-graphql-schema/package.json b/examples/extend-graphql-schema/package.json index e6dd1fab575..ad02a179778 100644 --- a/examples/extend-graphql-schema/package.json +++ b/examples/extend-graphql-schema/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-extend-graphql-schema", - "version": "1.0.6", + "version": "1.0.7", "private": true, "license": "MIT", "scripts": { @@ -9,11 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/extend-graphql-schema/schema.graphql b/examples/extend-graphql-schema/schema.graphql index 5268dc2c516..75d76e389ba 100644 --- a/examples/extend-graphql-schema/schema.graphql +++ b/examples/extend-graphql-schema/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Mutation { """ Publish a post @@ -40,16 +43,15 @@ enum PostStatusType { published } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: PostStatusTypeNullableFilter - content: StringNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -63,62 +65,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - content: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -171,31 +119,19 @@ type Author { postsCount(where: PostWhereInput! = {}): Int } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -298,6 +234,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/extend-graphql-schema/schema.prisma b/examples/extend-graphql-schema/schema.prisma index ba6c0a653db..33d6cc1f737 100644 --- a/examples/extend-graphql-schema/schema.prisma +++ b/examples/extend-graphql-schema/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/extend-graphql-schema/schema.ts b/examples/extend-graphql-schema/schema.ts index 0293cce7eb0..03a0990402f 100644 --- a/examples/extend-graphql-schema/schema.ts +++ b/examples/extend-graphql-schema/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Post: list({ @@ -20,7 +20,7 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), }, }), diff --git a/examples/json/CHANGELOG.md b/examples/json/CHANGELOG.md index 02b93900684..e7db50d177b 100644 --- a/examples/json/CHANGELOG.md +++ b/examples/json/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-json +## 4.0.8 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 4.0.7 ### Patch Changes diff --git a/examples/json/keystone.ts b/examples/json/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/json/keystone.ts +++ b/examples/json/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/json/package.json b/examples/json/package.json index 683425f4541..72fdf6d4875 100644 --- a/examples/json/package.json +++ b/examples/json/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-json-field", - "version": "4.0.7", + "version": "4.0.8", "private": true, "license": "MIT", "scripts": { @@ -9,11 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/json/schema.graphql b/examples/json/schema.graphql index d474f50471c..45b03572944 100644 --- a/examples/json/schema.graphql +++ b/examples/json/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Package { id: ID! label: String @@ -6,14 +9,15 @@ type Package { ownedBy: Person } +input PackageWhereUniqueInput { + id: ID +} + input PackageWhereInput { AND: [PackageWhereInput!] OR: [PackageWhereInput!] NOT: [PackageWhereInput!] id: IDFilter - label: StringNullableFilter - isPrivate: BooleanNullableFilter - ownedBy: PersonWhereInput } input IDFilter { @@ -27,47 +31,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input BooleanNullableFilter { - equals: Boolean - not: BooleanNullableFilter -} - -input PackageWhereUniqueInput { - id: ID -} - input PackageOrderByInput { id: OrderDirection - label: OrderDirection - isPrivate: OrderDirection } enum OrderDirection { @@ -117,28 +82,19 @@ type Person { packagesCount(where: PackageWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] NOT: [PersonWhereInput!] id: IDFilter - name: StringNullableFilter - packages: PackageManyRelationFilter -} - -input PackageManyRelationFilter { - every: PackageWhereInput - some: PackageWhereInput - none: PackageWhereInput -} - -input PersonWhereUniqueInput { - id: ID } input PersonOrderByInput { id: OrderDirection - name: OrderDirection } input PersonUpdateInput { @@ -248,6 +204,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/json/schema.prisma b/examples/json/schema.prisma index 09e3e8115df..7e77ac3aea3 100644 --- a/examples/json/schema.prisma +++ b/examples/json/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/json/schema.ts b/examples/json/schema.ts index 34ec355e3f7..2eaf23d0815 100644 --- a/examples/json/schema.ts +++ b/examples/json/schema.ts @@ -1,5 +1,5 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, json, relationship, text } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, json, relationship, text } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Package: list({ diff --git a/examples/task-manager/CHANGELOG.md b/examples/task-manager/CHANGELOG.md index 7ffa163a889..b6619246c15 100644 --- a/examples/task-manager/CHANGELOG.md +++ b/examples/task-manager/CHANGELOG.md @@ -1,5 +1,16 @@ # @keystone-next/example-task-manager +## 4.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +* [#6370](https://github.com/keystonejs/keystone/pull/6370) [`9d8ae78ff`](https://github.com/keystonejs/keystone/commit/9d8ae78ffacbff7f2e41a8ec5ba2ca7cf320834a) Thanks [@bladey](https://github.com/bladey)! - Adds ability to seed data for `blog` and `task-manager` examples. Use `yarn seed-data` in either examples folder to create a set of example data. + +* Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 4.0.6 ### Patch Changes diff --git a/examples/task-manager/README.md b/examples/task-manager/README.md index 03066141ffa..87431499f2d 100644 --- a/examples/task-manager/README.md +++ b/examples/task-manager/README.md @@ -2,28 +2,32 @@ This base project implements a simple **Task Management** app, with `Tasks` and `People` who can be assigned to tasks. -You can it as a starting place for learning how to use Keystone. -It’s also a starter for other [feature projects](../). +Use it as a starting place for learning how to use Keystone. ## Instructions -To run this project, clone the Keystone repository locally then navigate to this directory and run: +To run this project: -```shell -yarn dev -``` +1. Clone the Keystone repository locally +2. Navigate to this directory `cd examples/task-manager` +3. Run `yarn dev` -This will start the Admin UI at [localhost:3000](http://localhost:3000). +This will start Keystone’s Admin UI at [localhost:3000](http://localhost:3000), where you can add items to an empty database. -You can use the Admin UI to create items in your database. +You can also access Keystone’s GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql) to explore the GraphQL API, and run [queries](https://keystonejs.com/docs/guides/filters) and [mutations](https://keystonejs.com/docs/apis/graphql#mutations) on your data. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +Congratulations, you’re now up and running with Keystone! 🚀 -🚀 Congratulations, you're now up and running with Keystone! +### Optional: add sample data + +This example includes sample data. To add it to your database: + +1. Ensure you’ve initialised your project with `yarn dev` at least once. +2. Run `yarn seed-data`. This will populate your database with sample content. +3. Run `yarn dev` again to startup Admin UI with sample data in place. ## Next steps -This project is bare bones, and doesn't use any of Keystone's advanced features. -We encourage you to experiment with the code here to see how Keystone works, become familiar with the Admin UI, and learn about the GraphQL Playground. +Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the GraphQL Playground. -When you've got the hang of the Task Manager, try a [feature project](../) to learn Keystone's advanced features and take your knowledge to the next level. +When you’ve got the hang of this base project, try a [feature project](../) to learn Keystone’s advanced features and take your knowledge to the next level. diff --git a/examples/task-manager/keystone.ts b/examples/task-manager/keystone.ts index e961168f85e..89001a1390f 100644 --- a/examples/task-manager/keystone.ts +++ b/examples/task-manager/keystone.ts @@ -1,10 +1,16 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; +import { insertSeedData } from './seed-data'; export default config({ db: { provider: 'sqlite', url: process.env.DATABASE_URL || 'file:./keystone-example.db', + async onConnect(context) { + if (process.argv.includes('--seed-data')) { + await insertSeedData(context); + } + }, }, lists, }); diff --git a/examples/task-manager/package.json b/examples/task-manager/package.json index 8680a007e74..b383afca1c8 100644 --- a/examples/task-manager/package.json +++ b/examples/task-manager/package.json @@ -1,19 +1,19 @@ { "name": "@keystone-next/example-task-manager", - "version": "4.0.6", + "version": "4.0.7", "private": true, "license": "MIT", "scripts": { "dev": "keystone-next dev", "start": "keystone-next start", - "build": "keystone-next build" + "build": "keystone-next build", + "seed-data": "keystone-next --seed-data" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/task-manager/schema.graphql b/examples/task-manager/schema.graphql index e194b7cb406..24200845cd6 100644 --- a/examples/task-manager/schema.graphql +++ b/examples/task-manager/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Task { id: ID! label: String @@ -13,6 +16,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -87,10 +94,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -148,6 +151,10 @@ type Person { tasksCount(where: TaskWhereInput! = {}): Int } +input PersonWhereUniqueInput { + id: ID +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -163,10 +170,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -276,6 +279,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/task-manager/schema.prisma b/examples/task-manager/schema.prisma index a1efaced2f7..78461ee962d 100644 --- a/examples/task-manager/schema.prisma +++ b/examples/task-manager/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/task-manager/schema.ts b/examples/task-manager/schema.ts index 9b539803be8..d76a4cb034d 100644 --- a/examples/task-manager/schema.ts +++ b/examples/task-manager/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -18,11 +18,15 @@ export const lists = createSchema({ assignedTo: relationship({ ref: 'Person.tasks', many: false }), finishBy: timestamp(), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/task-manager/seed-data/data.ts b/examples/task-manager/seed-data/data.ts new file mode 100644 index 00000000000..015886479c8 --- /dev/null +++ b/examples/task-manager/seed-data/data.ts @@ -0,0 +1,72 @@ +export const persons = [ + { name: 'Lucy Wroblewski' }, + { name: 'Ches Adebayor' }, + { name: 'Tiff Jayden' }, + { name: 'Henrique Urrea' }, +]; + +export const tasks = [ + { + label: 'Install Keystone in local dev 🧪', + isComplete: true, + finishBy: '2021-01-01T02:30:00.000Z', + assignedTo: 'Lucy Wroblewski', + priority: 'high', + }, + { + label: 'Model the content💡', + isComplete: true, + finishBy: '2021-01-22T05:43:51.000Z', + assignedTo: 'Ches Adebayor', + priority: 'high', + }, + { + label: 'Architect the data schema 🔗', + isComplete: true, + finishBy: '2021-02-02T20:02:37.000Z', + assignedTo: 'Lucy Wroblewski', + priority: 'high', + }, + { + label: 'Design the UI 💅🏼', + isComplete: true, + finishBy: '2021-02-24T22:17:07.000Z', + assignedTo: 'Tiff Jayden', + priority: 'medium', + }, + { + label: 'Publish the content 📝', + isComplete: true, + finishBy: '2021-03-01T05:41:37.000Z', + assignedTo: 'Ches Adebayor', + priority: 'low', + }, + { + label: 'Query content over GraphQL🔎', + isComplete: false, + finishBy: '2021-03-21T05:41:37.000Z', + assignedTo: 'Lucy Wroblewski', + priority: 'medium', + }, + { + label: 'Implement the UI design in code 🖼', + isComplete: false, + finishBy: '2021-03-23T05:41:37.000Z', + assignedTo: 'Henrique Urrea', + priority: 'medium', + }, + { + label: 'Deploy Keystone backend to the web ☁️', + isComplete: false, + finishBy: '2021-03-30T05:41:37.000Z', + assignedTo: 'Lucy Wroblewski', + priority: 'low', + }, + { + label: 'Launch project 🚀', + isComplete: false, + finishBy: '2021-04-01T05:41:37.000Z', + assignedTo: 'Lucy Wroblewski', + priority: 'low', + }, +]; diff --git a/examples/task-manager/seed-data/index.ts b/examples/task-manager/seed-data/index.ts new file mode 100644 index 00000000000..d300c81f7b5 --- /dev/null +++ b/examples/task-manager/seed-data/index.ts @@ -0,0 +1,66 @@ +import { KeystoneContext } from '@keystone-next/keystone/types'; +import { persons, tasks } from './data'; + +type PersonProps = { + name: string; +}; + +type TaskProps = { + label: string; + isComplete: Boolean; + finishBy: string; + assignedTo: Object; + person?: Object; +}; + +export async function insertSeedData(context: KeystoneContext) { + console.log(`🌱 Inserting seed data`); + + const createPerson = async (personData: PersonProps) => { + let person = null; + try { + person = await context.lists.Person.findOne({ + where: { name: personData.name }, + query: 'id', + }); + } catch (e) {} + if (!person) { + person = await context.lists.Person.createOne({ + data: personData, + query: 'id', + }); + } + return person; + }; + + const createTask = async (taskData: TaskProps) => { + let persons; + try { + persons = await context.lists.Person.findMany({ + where: { name: { equals: taskData.assignedTo } }, + query: 'id', + }); + } catch (e) { + persons = []; + } + taskData.assignedTo = { connect: { id: persons[0].id } }; + const task = await context.lists.Task.createOne({ + data: taskData, + query: 'id', + }); + return task; + }; + + for (const person of persons) { + console.log(`👩 Adding person: ${person.name}`); + await createPerson(person); + } + for (const task of tasks) { + console.log(`🔘 Adding task: ${task.label}`); + await createTask(task); + } + + console.log(`✅ Seed data inserted`); + console.log(`👋 Please start the process with \`yarn dev\` or \`npm run dev\``); + process.exit(); +} diff --git a/examples/testing/CHANGELOG.md b/examples/testing/CHANGELOG.md index 2b4114cecb1..596c30e5a59 100644 --- a/examples/testing/CHANGELOG.md +++ b/examples/testing/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-testing +## 0.0.7 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + ## 0.0.6 ### Patch Changes diff --git a/examples/testing/README.md b/examples/testing/README.md index ad49944a828..3550968aa0e 100644 --- a/examples/testing/README.md +++ b/examples/testing/README.md @@ -18,7 +18,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features -Keystone provides a testing library in the package [`@keystone-next/testing`](https://keystonejs.com/guides/testing) which helps you write tests using [Jest](https://jestjs.io/). +Keystone provides a testing library in [`@keystone-next/keystone/testing`](https://keystonejs.com/guides/testing) which helps you write tests using [Jest](https://jestjs.io/). This example project uses this library to add tests to the [`withAuth()`](../with-auth) example project. The tests can be found in [example.test.ts](./example.test.ts) ### Running tests @@ -63,7 +63,7 @@ Ran all test suites. The function `setupTestRunner` takes the project's `KeystoneConfig` object and creates a `runner` function. This test runner is then used to wrap a test function. ```typescript -import { setupTestRunner } from '@keystone-next/testing'; +import { setupTestRunner } from '@keystone-next/keystone/testing'; import config from './keystone'; const runner = setupTestRunner({ config }); @@ -127,8 +127,8 @@ test( The function `setupTestEnv` is used to set up a test environment which can be used across multiple tests. ```typescript -import { KeystoneContext } from '@keystone-next/types'; -import { setupTestEnv, TestEnv } from '@keystone-next/testing'; +import { KeystoneContext } from '@keystone-next/keystone/types'; +import { setupTestEnv, TestEnv } from '@keystone-next/keystone/testing'; import config from './keystone'; describe('Example tests using test environment', () => { diff --git a/examples/testing/babel.config.js b/examples/testing/babel.config.js index a8114fee85d..5c2f807ce8f 100644 --- a/examples/testing/babel.config.js +++ b/examples/testing/babel.config.js @@ -23,10 +23,4 @@ module.exports = { '@babel/proposal-object-rest-spread', '@babel/plugin-syntax-dynamic-import', ], - overrides: [ - { - include: 'packages/fields/src/Controller.js', - presets: ['@babel/preset-env'], - }, - ], }; diff --git a/examples/testing/example.test.ts b/examples/testing/example.test.ts index 5bdf91d8ac7..a8d152c9e90 100644 --- a/examples/testing/example.test.ts +++ b/examples/testing/example.test.ts @@ -1,5 +1,5 @@ -import { KeystoneContext } from '@keystone-next/types'; -import { setupTestEnv, setupTestRunner, TestEnv } from '@keystone-next/testing'; +import { KeystoneContext } from '@keystone-next/keystone/types'; +import { setupTestEnv, setupTestRunner, TestEnv } from '@keystone-next/keystone/testing'; import config from './keystone'; // Setup a test runner which will provide a clean test environment diff --git a/examples/testing/keystone.ts b/examples/testing/keystone.ts index 4c61b4cf511..b872e200e6f 100644 --- a/examples/testing/keystone.ts +++ b/examples/testing/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import { lists } from './schema'; diff --git a/examples/testing/package.json b/examples/testing/package.json index e094b5328f9..561a158816c 100644 --- a/examples/testing/package.json +++ b/examples/testing/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-testing", - "version": "0.0.6", + "version": "0.0.7", "private": true, "license": "MIT", "scripts": { @@ -13,16 +13,13 @@ "@babel/core": "^7.15.0", "@babel/preset-env": "^7.15.0", "@babel/preset-typescript": "^7.15.0", - "@keystone-next/auth": "^31.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/testing": "^1.1.1", - "@keystone-next/types": "^24.0.0" + "@keystone-next/auth": "^32.0.0", + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "babel-jest": "^27.0.6", - "jest": "^27.0.6", - "typescript": "^4.3.5" + "babel-jest": "^27.1.0", + "jest": "^27.1.0", + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/testing/schema.graphql b/examples/testing/schema.graphql index c6a5ddc8586..c37b0c90fde 100644 --- a/examples/testing/schema.graphql +++ b/examples/testing/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + input CreateInitialPersonInput { name: String email: String @@ -66,6 +69,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -140,10 +147,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -207,6 +210,11 @@ type PasswordState { isSet: Boolean! } +input PersonWhereUniqueInput { + id: ID + email: String +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -228,11 +236,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID - email: String -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -333,6 +336,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/testing/schema.prisma b/examples/testing/schema.prisma index 1d408eddef9..56ac89a216f 100644 --- a/examples/testing/schema.prisma +++ b/examples/testing/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/testing/schema.ts b/examples/testing/schema.ts index 3949439b06c..6d2e24930c6 100644 --- a/examples/testing/schema.ts +++ b/examples/testing/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, password, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, password, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -21,21 +21,27 @@ export const lists = createSchema({ // Add access control so that only the assigned user can update a task // We will write a test to verify that this is working correctly. access: { - update: async ({ session, itemId, context }) => { - const task = await context.lists.Task.findOne({ - where: { id: itemId }, - query: 'assignedTo { id }', - }); - return !!(session?.itemId && session.itemId === task.assignedTo?.id); + item: { + update: async ({ session, item, context }) => { + const task = await context.lists.Task.findOne({ + where: { id: item.id }, + query: 'assignedTo { id }', + }); + return !!(session?.itemId && session.itemId === task.assignedTo?.id); + }, }, }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), password: password({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/examples/virtual-field/CHANGELOG.md b/examples/virtual-field/CHANGELOG.md index 87b027c8237..d4f07041189 100644 --- a/examples/virtual-field/CHANGELOG.md +++ b/examples/virtual-field/CHANGELOG.md @@ -1,5 +1,14 @@ # @keystone-next/example-virtual-field +## 0.1.5 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + ## 0.1.4 ### Patch Changes diff --git a/examples/virtual-field/README.md b/examples/virtual-field/README.md index fd452f6068f..713748da176 100644 --- a/examples/virtual-field/README.md +++ b/examples/virtual-field/README.md @@ -19,7 +19,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features This project demonstrates how to use virtual fields. -It uses the `schema` API from the `@keystone-next/types` package to define the GraphQL schema used by the virtual fields. +It uses the `graphql` export from `@keystone-next/keystone` to define the GraphQL schema used by the virtual fields. ### `isPublished` @@ -27,8 +27,8 @@ The `isPublished` field shows how to use the `virtual` field to return some deri ```ts isPublished: virtual({ - field: schema.field({ - type: schema.Boolean, + field: graphql.field({ + type: graphql.Boolean, resolve(item: any) { return item.status === 'published'; }, @@ -42,24 +42,24 @@ The `counts` field shows how to return a GraphQL object rather than a scalar fro ```ts counts: virtual({ - field: schema.field({ - type: schema.object<{ content: string }>()({ + field: graphql.field({ + type: graphql.object<{ content: string }>()({ name: 'PostCounts', fields: { - words: schema.field({ - type: schema.Int, + words: graphql.field({ + type: graphql.Int, resolve({ content }) { return content.split(' ').length; }, }), - sentences: schema.field({ - type: schema.Int, + sentences: graphql.field({ + type: graphql.Int, resolve({ content }) { return content.split('.').length; }, }), - paragraphs: schema.field({ - type: schema.Int, + paragraphs: graphql.field({ + type: graphql.Int, resolve({ content }) { return content.split('\n\n').length; }, @@ -80,10 +80,10 @@ The `excerpt` field shows how to add GraphQL arguments to a virtual field. ```ts excerpt: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, args: { - length: schema.arg({ type: schema.nonNull(schema.Int), defaultValue: 200 }), + length: graphql.arg({ type: graphql.nonNull(graphql.Int), defaultValue: 200 }), }, resolve(item, { length }) { if (!item.content) { @@ -102,8 +102,8 @@ The `relatedPosts` field shows how to use the GraphQL types defined by a Keyston ```ts relatedPosts: virtual({ field: lists => - schema.field({ - type: schema.list(schema.nonNull(lists.Post.types.output)), + graphql.field({ + type: graphql.list(graphql.nonNull(lists.Post.types.output)), resolve(item, args, context) { // this could have some logic to get posts that are actually related to this one somehow // this is a just a naive "get the three latest posts that aren't this one" diff --git a/examples/virtual-field/keystone.ts b/examples/virtual-field/keystone.ts index e961168f85e..ba5fa75f414 100644 --- a/examples/virtual-field/keystone.ts +++ b/examples/virtual-field/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { lists } from './schema'; export default config({ diff --git a/examples/virtual-field/package.json b/examples/virtual-field/package.json index 6744cd3dc4e..cd9ddc93dd8 100644 --- a/examples/virtual-field/package.json +++ b/examples/virtual-field/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-virtual-field", - "version": "0.1.4", + "version": "0.1.5", "private": true, "license": "MIT", "scripts": { @@ -9,12 +9,10 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0" + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/virtual-field/schema.graphql b/examples/virtual-field/schema.graphql index 2a1713840d0..1ad3971c405 100644 --- a/examples/virtual-field/schema.graphql +++ b/examples/virtual-field/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + type Post { id: ID! title: String @@ -22,16 +25,15 @@ type PostCounts { paragraphs: Int } +input PostWhereUniqueInput { + id: ID +} + input PostWhereInput { AND: [PostWhereInput!] OR: [PostWhereInput!] NOT: [PostWhereInput!] id: IDFilter - title: StringNullableFilter - status: PostStatusTypeNullableFilter - content: StringNullableFilter - publishDate: DateTimeNullableFilter - author: AuthorWhereInput } input IDFilter { @@ -45,62 +47,8 @@ input IDFilter { not: IDFilter } -input StringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input PostStatusTypeNullableFilter { - equals: PostStatusType - in: [PostStatusType!] - notIn: [PostStatusType!] - not: PostStatusTypeNullableFilter -} - -input DateTimeNullableFilter { - equals: String - in: [String!] - notIn: [String!] - lt: String - lte: String - gt: String - gte: String - not: DateTimeNullableFilter -} - -input PostWhereUniqueInput { - id: ID -} - input PostOrderByInput { id: OrderDirection - title: OrderDirection - status: OrderDirection - content: OrderDirection - publishDate: OrderDirection } enum OrderDirection { @@ -154,31 +102,19 @@ type Author { latestPost: Post } +input AuthorWhereUniqueInput { + id: ID +} + input AuthorWhereInput { AND: [AuthorWhereInput!] OR: [AuthorWhereInput!] NOT: [AuthorWhereInput!] id: IDFilter - name: StringNullableFilter - email: StringNullableFilter - posts: PostManyRelationFilter -} - -input PostManyRelationFilter { - every: PostWhereInput - some: PostWhereInput - none: PostWhereInput -} - -input AuthorWhereUniqueInput { - id: ID - email: String } input AuthorOrderByInput { id: OrderDirection - name: OrderDirection - email: OrderDirection } input AuthorUpdateInput { @@ -287,6 +223,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/virtual-field/schema.prisma b/examples/virtual-field/schema.prisma index ba6c0a653db..33d6cc1f737 100644 --- a/examples/virtual-field/schema.prisma +++ b/examples/virtual-field/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/virtual-field/schema.ts b/examples/virtual-field/schema.ts index 3dbba311fae..4de75620aa1 100644 --- a/examples/virtual-field/schema.ts +++ b/examples/virtual-field/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { select, relationship, text, timestamp, virtual } from '@keystone-next/fields'; -import { schema } from '@keystone-next/types'; +import { createSchema, list } from '@keystone-next/keystone'; +import { select, relationship, text, timestamp, virtual } from '@keystone-next/keystone/fields'; +import { graphql } from '@keystone-next/keystone/types'; export const lists = createSchema({ Post: list({ @@ -15,8 +15,8 @@ export const lists = createSchema({ }), // A virtual field returning a value derived from the item data. isPublished: virtual({ - field: schema.field({ - type: schema.Boolean, + field: graphql.field({ + type: graphql.Boolean, resolve(item: any) { return item.status === 'published'; }, @@ -25,17 +25,17 @@ export const lists = createSchema({ content: text({ ui: { displayMode: 'textarea' } }), // A virtual field returning a custom GraphQL object type. counts: virtual({ - field: schema.field({ - type: schema.object<{ + field: graphql.field({ + type: graphql.object<{ words: number; sentences: number; paragraphs: number; }>()({ name: 'PostCounts', fields: { - words: schema.field({ type: schema.Int }), - sentences: schema.field({ type: schema.Int }), - paragraphs: schema.field({ type: schema.Int }), + words: graphql.field({ type: graphql.Int }), + sentences: graphql.field({ type: graphql.Int }), + paragraphs: graphql.field({ type: graphql.Int }), }, }), resolve(item: any) { @@ -51,10 +51,10 @@ export const lists = createSchema({ }), // A virtual field which accepts GraphQL arguments. excerpt: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, args: { - length: schema.arg({ type: schema.nonNull(schema.Int), defaultValue: 200 }), + length: graphql.arg({ type: graphql.nonNull(graphql.Int), defaultValue: 200 }), }, resolve(item, { length }) { if (!item.content) { @@ -74,8 +74,8 @@ export const lists = createSchema({ author: relationship({ ref: 'Author.posts', many: false }), // A virtual field which uses `item` and `context` to query data. authorName: virtual({ - field: schema.field({ - type: schema.String, + field: graphql.field({ + type: graphql.String, async resolve(item, args, context) { const { author } = await context.lists.Post.findOne({ where: { id: item.id.toString() }, @@ -90,12 +90,12 @@ export const lists = createSchema({ Author: list({ fields: { name: text({ isRequired: true }), - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique' }), posts: relationship({ ref: 'Post.author', many: true }), // A virtual field which returns a type derived from a Keystone list. latestPost: virtual({ field: lists => - schema.field({ + graphql.field({ type: lists.Post.types.output, async resolve(item, args, context) { const { posts } = await context.lists.Author.findOne({ diff --git a/examples/with-auth/CHANGELOG.md b/examples/with-auth/CHANGELOG.md index e179b27cebf..9c18b05cde4 100644 --- a/examples/with-auth/CHANGELOG.md +++ b/examples/with-auth/CHANGELOG.md @@ -1,5 +1,15 @@ # @keystone-next/example-with-auth +## 2.0.8 + +### Patch Changes + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-next/auth@32.0.0 + ## 2.0.7 ### Patch Changes diff --git a/examples/with-auth/README.md b/examples/with-auth/README.md index 1d1bda7738d..8e922b9e6fa 100644 --- a/examples/with-auth/README.md +++ b/examples/with-auth/README.md @@ -34,7 +34,7 @@ We add two new fields, `email` and `password`, to the `Person` list. These are used as our _identity_ and _secret_ fields for login. ```typescript - email: text({ isRequired: true, isUnique: true }), + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), password: password({ isRequired: true }), ``` diff --git a/examples/with-auth/keystone.ts b/examples/with-auth/keystone.ts index 4c61b4cf511..b872e200e6f 100644 --- a/examples/with-auth/keystone.ts +++ b/examples/with-auth/keystone.ts @@ -1,4 +1,4 @@ -import { config } from '@keystone-next/keystone/schema'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import { lists } from './schema'; diff --git a/examples/with-auth/package.json b/examples/with-auth/package.json index a9cefb11b89..f06c93de849 100644 --- a/examples/with-auth/package.json +++ b/examples/with-auth/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/example-with-auth", - "version": "2.0.7", + "version": "2.0.8", "private": true, "license": "MIT", "scripts": { @@ -9,12 +9,11 @@ "build": "keystone-next build" }, "dependencies": { - "@keystone-next/auth": "^31.0.0", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0" + "@keystone-next/auth": "^32.0.0", + "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/with-auth/schema.graphql b/examples/with-auth/schema.graphql index c6a5ddc8586..c37b0c90fde 100644 --- a/examples/with-auth/schema.graphql +++ b/examples/with-auth/schema.graphql @@ -1,3 +1,6 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + input CreateInitialPersonInput { name: String email: String @@ -66,6 +69,10 @@ enum TaskPriorityType { high } +input TaskWhereUniqueInput { + id: ID +} + input TaskWhereInput { AND: [TaskWhereInput!] OR: [TaskWhereInput!] @@ -140,10 +147,6 @@ input DateTimeNullableFilter { not: DateTimeNullableFilter } -input TaskWhereUniqueInput { - id: ID -} - input TaskOrderByInput { id: OrderDirection label: OrderDirection @@ -207,6 +210,11 @@ type PasswordState { isSet: Boolean! } +input PersonWhereUniqueInput { + id: ID + email: String +} + input PersonWhereInput { AND: [PersonWhereInput!] OR: [PersonWhereInput!] @@ -228,11 +236,6 @@ input TaskManyRelationFilter { none: TaskWhereInput } -input PersonWhereUniqueInput { - id: ID - email: String -} - input PersonOrderByInput { id: OrderDirection name: OrderDirection @@ -333,6 +336,7 @@ type KeystoneAdminUIFieldMeta { path: String! label: String! isOrderable: Boolean! + isFilterable: Boolean! fieldMeta: JSON viewsIndex: Int! customViewsIndex: Int diff --git a/examples/with-auth/schema.prisma b/examples/with-auth/schema.prisma index 1d408eddef9..56ac89a216f 100644 --- a/examples/with-auth/schema.prisma +++ b/examples/with-auth/schema.prisma @@ -1,3 +1,6 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + datasource sqlite { url = env("DATABASE_URL") provider = "sqlite" diff --git a/examples/with-auth/schema.ts b/examples/with-auth/schema.ts index 4be26920552..bb286a09ad8 100644 --- a/examples/with-auth/schema.ts +++ b/examples/with-auth/schema.ts @@ -1,6 +1,6 @@ -import { createSchema, list } from '@keystone-next/keystone/schema'; -import { checkbox, password, relationship, text, timestamp } from '@keystone-next/fields'; -import { select } from '@keystone-next/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { checkbox, password, relationship, text, timestamp } from '@keystone-next/keystone/fields'; +import { select } from '@keystone-next/keystone/fields'; export const lists = createSchema({ Task: list({ @@ -18,19 +18,23 @@ export const lists = createSchema({ assignedTo: relationship({ ref: 'Person.tasks', many: false }), finishBy: timestamp(), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), Person: list({ fields: { name: text({ isRequired: true }), // Added an email and password pair to be used with authentication // The email address is going to be used as the identity field, so it's - // important that we set both isRequired and isUnique - email: text({ isRequired: true, isUnique: true }), + // important that we set isRequired, isIndexed: 'unique', and isFilterable. + email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }), // The password field stores a hash of the supplied password, and // we want to ensure that all people have a password set, so we use // the isRequired flag. password: password({ isRequired: true }), tasks: relationship({ ref: 'Task.assignedTo', many: true }), }, + defaultIsFilterable: true, + defaultIsOrderable: true, }), }); diff --git a/package.json b/package.json index 0cbf8275d20..b70c0eaeedc 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "npm-tag": "manypkg npm-tag", "update": "manypkg upgrade", "no-cypress-install": "cross-env CYPRESS_INSTALL_BINARY=0 yarn", - "postinstall-examples": "for d in `find examples -type d -maxdepth 1 -mindepth 1`; do cd $d; yarn keystone-next postinstall --fix; cd ../..; done; for d in `find examples-staging -type d -maxdepth 1 -mindepth 1`; do cd $d; yarn keystone-next postinstall --fix; cd ../..; done; for d in `find tests/test-projects -type d -maxdepth 1 -mindepth 1`; do cd $d; yarn keystone-next postinstall --fix; cd ../..; done", + "postinstall-examples": "for d in `find examples -type d -maxdepth 1 -mindepth 1`; do echo $d; cd $d; yarn keystone-next postinstall --fix; cd ../..; done; for d in `find examples-staging -type d -maxdepth 1 -mindepth 1`; do echo $d; cd $d; yarn keystone-next postinstall --fix; cd ../..; done; for d in `find tests/test-projects -type d -maxdepth 1 -mindepth 1`; do echo $d; cd $d; yarn keystone-next postinstall --fix; cd ../../..; done", "lint:examples": "for d in `find examples -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done; for d in `find examples-staging -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../..; done; for d in `find tests/test-projects -type d -maxdepth 1 -mindepth 1`; do cd $d; echo $d; SKIP_PROMPTS=1 yarn keystone-next postinstall; if [ $? -ne 0 ]; then exit 1; fi; cd ../../..; done", "generate-filters": "cd prisma-utils && yarn generate", "lint:filters": "cd prisma-utils && yarn verify" @@ -48,27 +48,27 @@ "@babel/preset-env": "^7.15.0", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", - "@changesets/changelog-github": "^0.4.0", - "@changesets/cli": "^2.16.0", - "@jest/test-sequencer": "^27.0.6", + "@changesets/changelog-github": "^0.4.1", + "@changesets/cli": "^2.17.0", + "@jest/test-sequencer": "^27.1.0", "@manypkg/cli": "^0.18.0", - "@preconstruct/cli": "2.1.0", + "@preconstruct/cli": "2.1.1", "@preconstruct/eslint-plugin-format-js-tag": "^0.1.0", "@testing-library/jest-dom": "^5.14.1", "@types/jest": "^27.0.1", "@types/node-fetch": "^2.5.12", - "@typescript-eslint/eslint-plugin": "^4.29.2", - "@typescript-eslint/parser": "^4.29.2", + "@typescript-eslint/eslint-plugin": "^4.30.0", + "@typescript-eslint/parser": "^4.30.0", "chalk-cli": "^4.1.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", "eslint-plugin-cypress": "^2.11.3", - "eslint-plugin-import": "^2.24.0", + "eslint-plugin-import": "^2.24.2", "eslint-plugin-jest": "^24.4.0", - "eslint-plugin-react": "^7.24.0", + "eslint-plugin-react": "^7.25.1", "eslint-plugin-react-hooks": "^4.2.0", "is-ci": "^3.0.0", - "jest": "^27.0.6", + "jest": "^27.1.0", "prettier": "^2.3.2", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -77,7 +77,7 @@ "remark-toc": "^5.1.1", "rimraf": "^3.0.2", "terminal-link-cli": "^3.0.0", - "typescript": "^4.3.5" + "typescript": "^4.4.2" }, "prettier": { "proseWrap": "preserve", @@ -151,8 +151,7 @@ "packages/**/*.{js,ts,tsx}", "!**/*.d.ts", "!packages/**/dist/**", - "!packages/fields/**/test-fixtures.{js,ts}", - "!packages/fields/types.js" + "!packages/keystone/src/fields/**/test-fixtures.{js,ts}" ] }, "resolutions": { diff --git a/packages/admin-ui-utils/CHANGELOG.md b/packages/admin-ui-utils/CHANGELOG.md index 5acd3fcae8d..097115e022e 100644 --- a/packages/admin-ui-utils/CHANGELOG.md +++ b/packages/admin-ui-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @keystone-next/admin-ui-utils +## 6.0.0 + +### Major Changes + +- [#6367](https://github.com/keystonejs/keystone/pull/6367) [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/admin-ui-utils` to `@keystone-next/keystone/admin-ui/utils` + ## 5.0.6 ### Patch Changes diff --git a/packages/admin-ui-utils/package.json b/packages/admin-ui-utils/package.json index 9a0ba81f77b..15df8dc7318 100644 --- a/packages/admin-ui-utils/package.json +++ b/packages/admin-ui-utils/package.json @@ -1,24 +1,9 @@ { "name": "@keystone-next/admin-ui-utils", - "version": "5.0.6", + "version": "6.0.0", "main": "dist/admin-ui-utils.cjs.js", "module": "dist/admin-ui-utils.esm.js", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.15.3", - "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/core": "^3.1.1", - "@types/react": "^17.0.18", - "fast-deep-equal": "^3.1.3", - "graphql": "^15.5.1" - }, - "peerDependencies": { - "react": "^17.0.2" - }, - "devDependencies": { - "react": "^17.0.2" - }, "engines": { "node": "^12.20 || >= 14.13" }, diff --git a/packages/admin-ui-utils/src/index.ts b/packages/admin-ui-utils/src/index.ts index 98ff24e461c..316949451f5 100644 --- a/packages/admin-ui-utils/src/index.ts +++ b/packages/admin-ui-utils/src/index.ts @@ -1,6 +1,5 @@ -export * from './dataGetter'; -export * from './Fields'; -export * from './getRootGraphQLFieldsFromFieldController'; -export * from './item-form'; -export * from './serialization'; -export * from './useInvalidFields'; +throw new Error( + '`@keystone-next/admin-ui-utils` has been moved to `@keystone-next/keystone/admin-ui/utils`, please import from there instead.' +); + +export {}; diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index a37f9e59522..48e26077d2f 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,30 @@ # @keystone-next/auth +## 32.0.0 + +### Major Changes + +- [#6371](https://github.com/keystonejs/keystone/pull/6371) [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/types` to `@keystone-next/keystone/types` + +* [#6367](https://github.com/keystonejs/keystone/pull/6367) [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/admin-ui-utils` to `@keystone-next/keystone/admin-ui/utils` + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +* [#6437](https://github.com/keystonejs/keystone/pull/6437) [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed `isUnique: true` config in fields to `isIndexed: 'unique'` + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed the way the package directory for resolving views is obtained to use `__dirname` rather than `require.resolve('pkg/package.json')` because in Next.js 11 `require.resolve` returns a numeric id instead of the path. + +* [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +* Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/notice@4.0.2 + ## 31.0.0 ### Major Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index 1021aa7ca09..602a0a33fc8 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/auth", - "version": "31.0.0", + "version": "32.0.0", "license": "MIT", "main": "dist/auth.cjs.js", "module": "dist/auth.esm.js", @@ -9,24 +9,21 @@ }, "dependencies": { "@babel/runtime": "^7.15.3", - "@graphql-tools/schema": "^8.1.1", - "@keystone-next/admin-ui-utils": "^5.0.6", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.1", - "@keystone-ui/notice": "^4.0.1", + "@graphql-tools/schema": "^8.2.0", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/notice": "^4.0.2", "cross-fetch": "^3.1.4", "fast-deep-equal": "^3.1.3", - "graphql": "^15.5.1" + "graphql": "^15.5.2" }, "devDependencies": { - "@keystone-next/keystone": "^24.0.0", + "@keystone-next/keystone": "^25.0.0", "react": "^17.0.2" }, "peerDependencies": { - "@keystone-next/keystone": "^24.0.0", + "@keystone-next/keystone": "^25.0.0", "react": "^17.0.2" }, "preconstruct": { diff --git a/packages/auth/src/components/Icons.tsx b/packages/auth/src/components/Icons.tsx index 3455c923aac..b3e164ac908 100644 --- a/packages/auth/src/components/Icons.tsx +++ b/packages/auth/src/components/Icons.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { forwardRefWithAs, jsx } from '@keystone-ui/core'; diff --git a/packages/auth/src/components/SigninContainer.tsx b/packages/auth/src/components/SigninContainer.tsx index 6749e106617..1115a56f9eb 100644 --- a/packages/auth/src/components/SigninContainer.tsx +++ b/packages/auth/src/components/SigninContainer.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { ReactNode } from 'react'; diff --git a/packages/auth/src/gql/getBaseAuthSchema.ts b/packages/auth/src/gql/getBaseAuthSchema.ts index c5b54da3310..324d6e7ef25 100644 --- a/packages/auth/src/gql/getBaseAuthSchema.ts +++ b/packages/auth/src/gql/getBaseAuthSchema.ts @@ -1,4 +1,4 @@ -import type { GraphQLSchemaExtension, KeystoneContext } from '@keystone-next/types'; +import type { GraphQLSchemaExtension, KeystoneContext } from '@keystone-next/keystone/types'; import { AuthGqlNames, SecretFieldImpl } from '../types'; diff --git a/packages/auth/src/gql/getInitFirstItemSchema.ts b/packages/auth/src/gql/getInitFirstItemSchema.ts index e5a6648c5d2..7b0af597577 100644 --- a/packages/auth/src/gql/getInitFirstItemSchema.ts +++ b/packages/auth/src/gql/getInitFirstItemSchema.ts @@ -1,4 +1,4 @@ -import type { GraphQLSchemaExtension } from '@keystone-next/types'; +import type { GraphQLSchemaExtension } from '@keystone-next/keystone/types'; import { assertInputObjectType, GraphQLInputObjectType, GraphQLSchema, printType } from 'graphql'; import { AuthGqlNames, InitFirstItemConfig } from '../types'; diff --git a/packages/auth/src/gql/getMagicAuthLinkSchema.ts b/packages/auth/src/gql/getMagicAuthLinkSchema.ts index a7505e275c3..938bcdd0fbf 100644 --- a/packages/auth/src/gql/getMagicAuthLinkSchema.ts +++ b/packages/auth/src/gql/getMagicAuthLinkSchema.ts @@ -1,4 +1,4 @@ -import type { GraphQLSchemaExtension } from '@keystone-next/types'; +import type { GraphQLSchemaExtension } from '@keystone-next/keystone/types'; import { AuthGqlNames, AuthTokenTypeConfig, SecretFieldImpl } from '../types'; diff --git a/packages/auth/src/gql/getPasswordResetSchema.ts b/packages/auth/src/gql/getPasswordResetSchema.ts index 50266e7d5ac..31ae9c15d34 100644 --- a/packages/auth/src/gql/getPasswordResetSchema.ts +++ b/packages/auth/src/gql/getPasswordResetSchema.ts @@ -1,4 +1,4 @@ -import type { GraphQLSchemaExtension } from '@keystone-next/types'; +import type { GraphQLSchemaExtension } from '@keystone-next/keystone/types'; import { AuthGqlNames, AuthTokenTypeConfig, SecretFieldImpl } from '../types'; diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index bddf82767f5..89dd87a936b 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -6,8 +6,8 @@ import { KeystoneContext, AdminUIConfig, SessionStrategy, -} from '@keystone-next/types'; -import { password, timestamp } from '@keystone-next/fields'; +} from '@keystone-next/keystone/types'; +import { password, timestamp } from '@keystone-next/keystone/fields'; import { AuthConfig, AuthGqlNames } from './types'; import { getSchemaExtension } from './schema'; diff --git a/packages/auth/src/lib/createAuthToken.ts b/packages/auth/src/lib/createAuthToken.ts index ad9f5aee0d5..e7f6c015753 100644 --- a/packages/auth/src/lib/createAuthToken.ts +++ b/packages/auth/src/lib/createAuthToken.ts @@ -1,5 +1,5 @@ import { randomBytes } from 'crypto'; -import type { KeystoneDbAPI } from '@keystone-next/types'; +import type { KeystoneDbAPI } from '@keystone-next/keystone/types'; import { AuthTokenRequestErrorCode } from '../types'; import { findMatchingIdentity } from './findMatchingIdentity'; diff --git a/packages/auth/src/lib/findMatchingIdentity.ts b/packages/auth/src/lib/findMatchingIdentity.ts index 3297aacf5a8..9102adee112 100644 --- a/packages/auth/src/lib/findMatchingIdentity.ts +++ b/packages/auth/src/lib/findMatchingIdentity.ts @@ -1,4 +1,4 @@ -import type { KeystoneDbAPI } from '@keystone-next/types'; +import type { KeystoneDbAPI } from '@keystone-next/keystone/types'; import { AuthTokenRequestErrorCode } from '../types'; @@ -13,7 +13,7 @@ export async function findMatchingIdentity( try { const item = await dbItemAPI.findOne({ where: { [identityField]: identity } }); return { success: true, item }; - } catch (err) { + } catch (err: any) { if (err.message === 'You do not have access to this resource') { return { success: false, code: 'IDENTITY_NOT_FOUND' }; } diff --git a/packages/auth/src/lib/getErrorMessage.ts b/packages/auth/src/lib/getErrorMessage.ts index 42fc18ab302..e7dd3a17fd1 100644 --- a/packages/auth/src/lib/getErrorMessage.ts +++ b/packages/auth/src/lib/getErrorMessage.ts @@ -1,4 +1,4 @@ -import { KeystoneContext } from '@keystone-next/types'; +import { KeystoneContext } from '@keystone-next/keystone/types'; import { AuthTokenRedemptionErrorCode, AuthTokenRequestErrorCode, diff --git a/packages/auth/src/lib/validateAuthToken.ts b/packages/auth/src/lib/validateAuthToken.ts index ae5de7b0645..72d0acc2095 100644 --- a/packages/auth/src/lib/validateAuthToken.ts +++ b/packages/auth/src/lib/validateAuthToken.ts @@ -1,4 +1,4 @@ -import type { KeystoneDbAPI } from '@keystone-next/types'; +import type { KeystoneDbAPI } from '@keystone-next/keystone/types'; import { AuthTokenRedemptionErrorCode, SecretFieldImpl } from '../types'; import { validateSecret } from './validateSecret'; diff --git a/packages/auth/src/lib/validateSecret.ts b/packages/auth/src/lib/validateSecret.ts index 63679b9c0f5..a09fa243e30 100644 --- a/packages/auth/src/lib/validateSecret.ts +++ b/packages/auth/src/lib/validateSecret.ts @@ -1,4 +1,4 @@ -import type { KeystoneDbAPI } from '@keystone-next/types'; +import type { KeystoneDbAPI } from '@keystone-next/keystone/types'; import { PasswordAuthErrorCode, SecretFieldImpl } from '../types'; import { findMatchingIdentity } from './findMatchingIdentity'; diff --git a/packages/auth/src/pages/InitPage.tsx b/packages/auth/src/pages/InitPage.tsx index 57e6dc22c2a..3c5be40b691 100644 --- a/packages/auth/src/pages/InitPage.tsx +++ b/packages/auth/src/pages/InitPage.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { useEffect, useMemo, useState } from 'react'; import fetch from 'cross-fetch'; @@ -7,7 +8,7 @@ import { jsx, H1, Stack, Inline, VisuallyHidden } from '@keystone-ui/core'; import { Button } from '@keystone-ui/button'; import { Checkbox, TextInput } from '@keystone-ui/fields'; import { useRawKeystone } from '@keystone-next/keystone/admin-ui/context'; -import { FieldMeta } from '@keystone-next/types'; +import { FieldMeta } from '@keystone-next/keystone/types'; import isDeepEqual from 'fast-deep-equal'; import { gql, useMutation } from '@keystone-next/keystone/admin-ui/apollo'; @@ -18,7 +19,7 @@ import { Fields, serializeValueToObjByFieldKey, useInvalidFields, -} from '@keystone-next/admin-ui-utils'; +} from '@keystone-next/keystone/admin-ui/utils'; import { guessEmailFromValue, validEmail } from '../lib/emailHeuristics'; import { IconTwitter, IconGithub } from '../components/Icons'; import { SigninContainer } from '../components/SigninContainer'; diff --git a/packages/auth/src/pages/SigninPage.tsx b/packages/auth/src/pages/SigninPage.tsx index 57d6e881181..07970779300 100644 --- a/packages/auth/src/pages/SigninPage.tsx +++ b/packages/auth/src/pages/SigninPage.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { useState, Fragment, FormEvent, useRef, useEffect } from 'react'; diff --git a/packages/auth/src/schema.ts b/packages/auth/src/schema.ts index 64cbef1e917..183d054bb9d 100644 --- a/packages/auth/src/schema.ts +++ b/packages/auth/src/schema.ts @@ -1,5 +1,5 @@ import { mergeSchemas } from '@graphql-tools/schema'; -import { ExtendGraphqlSchema } from '@keystone-next/types'; +import { ExtendGraphqlSchema } from '@keystone-next/keystone/types'; import { assertObjectType, @@ -70,7 +70,8 @@ export const getSchemaExtension = throw new Error( `createAuth was called with an identityField of ${identityField} on the list ${listKey} ` + `but that field doesn't allow being searched uniquely with a String or ID. ` + - `You should likely add \`isUnique: true\` to the field at ${listKey}.${identityField}` + `You should likely add \`isIndexed: 'unique'\, isFilterable: true\` ` + + `to the field at ${listKey}.${identityField}` ); } return [ diff --git a/packages/auth/src/templates/init.ts b/packages/auth/src/templates/init.ts index d9682236eec..0ee81c6974f 100644 --- a/packages/auth/src/templates/init.ts +++ b/packages/auth/src/templates/init.ts @@ -1,4 +1,4 @@ -import { BaseGeneratedListTypes } from '@keystone-next/types'; +import { BaseGeneratedListTypes } from '@keystone-next/keystone/types'; import { AuthConfig } from '../types'; type InitTemplateArgs = { diff --git a/packages/auth/src/types.ts b/packages/auth/src/types.ts index 91de2bd4081..b314ad1d7df 100644 --- a/packages/auth/src/types.ts +++ b/packages/auth/src/types.ts @@ -1,4 +1,4 @@ -import { BaseGeneratedListTypes, KeystoneContext } from '@keystone-next/types'; +import { BaseGeneratedListTypes, KeystoneContext } from '@keystone-next/keystone/types'; export type AuthGqlNames = { CreateInitialInput: string; diff --git a/packages/cloudinary/CHANGELOG.md b/packages/cloudinary/CHANGELOG.md index 2ccbf371910..b891d4f09f8 100644 --- a/packages/cloudinary/CHANGELOG.md +++ b/packages/cloudinary/CHANGELOG.md @@ -1,5 +1,32 @@ # @keystone-next/cloudinary +## 7.0.0 + +### Major Changes + +- [#6323](https://github.com/keystonejs/keystone/pull/6323) [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed unused legacy filter code + +* [#6371](https://github.com/keystonejs/keystone/pull/6371) [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/types` to `@keystone-next/keystone/types` + +- [#6426](https://github.com/keystonejs/keystone/pull/6426) [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955) Thanks [@timleslie](https://github.com/timleslie)! - Update the Access Control API. This is a breaking change which impacts the security of all Keystone systems. + + See the [Access Control API](https://keystonejs.com/docs/apis/access-control) for a full description of the new API. + +### Patch Changes + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +* [#6437](https://github.com/keystonejs/keystone/pull/6437) [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed `isUnique: true` config in fields to `isIndexed: 'unique'` + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed the way the package directory for resolving views is obtained to use `__dirname` rather than `require.resolve('pkg/package.json')` because in Next.js 11 `require.resolve` returns a numeric id instead of the path. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/pill@5.0.1 + ## 6.0.6 ### Patch Changes diff --git a/packages/cloudinary/package.json b/packages/cloudinary/package.json index 5b96740dc23..88a44042203 100644 --- a/packages/cloudinary/package.json +++ b/packages/cloudinary/package.json @@ -1,24 +1,26 @@ { "name": "@keystone-next/cloudinary", - "version": "6.0.6", + "version": "7.0.0", "license": "MIT", "main": "dist/cloudinary.cjs.js", "module": "dist/cloudinary.esm.js", "dependencies": { "@babel/runtime": "^7.15.3", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.2", - "@keystone-ui/pill": "^5.0.0", - "@types/react": "^17.0.18", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/pill": "^5.0.1", + "@types/react": "^17.0.19", "cloudinary": "^1.26.3", "cuid": "^2.1.8", "graphql-upload": "^12.0.0", "react": "^17.0.2" }, + "peerDependencies": { + "@keystone-next/keystone": "^25.0.0" + }, "devDependencies": { + "@keystone-next/keystone": "^25.0.0", "mime": "^2.5.2" }, "engines": { diff --git a/packages/cloudinary/src/index.ts b/packages/cloudinary/src/index.ts index 937f643548f..cd29d08786e 100644 --- a/packages/cloudinary/src/index.ts +++ b/packages/cloudinary/src/index.ts @@ -4,9 +4,9 @@ import { BaseGeneratedListTypes, FieldTypeFunc, jsonFieldTypePolyfilledForSQLite, - schema, + graphql, FieldDefaultValue, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; import { FileUpload } from 'graphql-upload'; import cuid from 'cuid'; import cloudinary from 'cloudinary'; @@ -33,44 +33,44 @@ type CloudinaryImageFieldConfig>; + transformation: graphql.InferValueFromArg>; }) => string | null; }; -const outputType = schema.object()({ +const outputType = graphql.object()({ name: 'CloudinaryImage_File', fields: { - id: schema.field({ type: schema.ID }), + id: graphql.field({ type: graphql.ID }), // path: types.field({ type: types.String }), - filename: schema.field({ type: schema.String }), - originalFilename: schema.field({ type: schema.String }), - mimetype: schema.field({ type: schema.String }), - encoding: schema.field({ type: schema.String }), - publicUrl: schema.field({ type: schema.String }), - publicUrlTransformed: schema.field({ + filename: graphql.field({ type: graphql.String }), + originalFilename: graphql.field({ type: graphql.String }), + mimetype: graphql.field({ type: graphql.String }), + encoding: graphql.field({ type: graphql.String }), + publicUrl: graphql.field({ type: graphql.String }), + publicUrlTransformed: graphql.field({ args: { - transformation: schema.arg({ type: CloudinaryImageFormat }), + transformation: graphql.arg({ type: CloudinaryImageFormat }), }, - type: schema.String, + type: graphql.String, resolve(rootVal, args) { return rootVal.publicUrlTransformed(args); }, @@ -116,8 +116,8 @@ export const cloudinaryImage = ...config }: CloudinaryImageFieldConfig): FieldTypeFunc => meta => { - if ((config as any).isUnique) { - throw Error('isUnique is not a supported option for field type cloudinaryImage'); + if ((config as any).isIndexed === 'unique') { + throw Error("isIndexed: 'unique' is not a supported option for field type cloudinaryImage"); } const adapter = new CloudinaryAdapter(cloudinary); const resolveInput = async ( @@ -148,10 +148,10 @@ export const cloudinaryImage = return jsonFieldTypePolyfilledForSQLite(meta.provider, { ...config, input: { - create: { arg: schema.arg({ type: schema.Upload }), resolve: resolveInput }, - update: { arg: schema.arg({ type: schema.Upload }), resolve: resolveInput }, + create: { arg: graphql.arg({ type: graphql.Upload }), resolve: resolveInput }, + update: { arg: graphql.arg({ type: graphql.Upload }), resolve: resolveInput }, }, - output: schema.field({ + output: graphql.field({ type: outputType, resolve({ value }) { if (value === null) { @@ -163,16 +163,13 @@ export const cloudinaryImage = publicUrlTransformed: ({ transformation, }: { - transformation: schema.InferValueFromArg>; + transformation: graphql.InferValueFromArg>; }) => adapter.publicUrlTransformed(val, transformation ?? {}), ...val, }; }, }), - views: path.join( - path.dirname(require.resolve('@keystone-next/cloudinary/package.json')), - 'views' - ), + views: path.join(path.dirname(__dirname), 'views'), __legacy: { isRequired, defaultValue }, }); }; diff --git a/packages/cloudinary/src/test-fixtures.skip.ts b/packages/cloudinary/src/test-fixtures.skip.ts index 4db695da10c..a7aac8c2dbe 100644 --- a/packages/cloudinary/src/test-fixtures.skip.ts +++ b/packages/cloudinary/src/test-fixtures.skip.ts @@ -2,8 +2,7 @@ import fs from 'fs'; import mime from 'mime'; import { FileUpload, Upload } from 'graphql-upload'; import cloudinary from 'cloudinary'; -import { text } from '@keystone-next/fields'; -import { DatabaseProvider } from '@keystone-next/types'; +import { DatabaseProvider } from '@keystone-next/keystone/types'; import { cloudinaryImage } from './index'; const path = require('path'); @@ -51,7 +50,6 @@ export const fieldConfig = () => ({ }, }); export const getTestFields = () => ({ - name: text(), image: cloudinaryImage({ cloudinary: { cloudName: process.env.CLOUDINARY_CLOUD_NAME || 'cloudinary_cloud_name', diff --git a/packages/cloudinary/src/views/Field.tsx b/packages/cloudinary/src/views/Field.tsx index 4f6b5614631..ae17ac1b360 100644 --- a/packages/cloudinary/src/views/Field.tsx +++ b/packages/cloudinary/src/views/Field.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, Stack, useTheme } from '@keystone-ui/core'; @@ -6,7 +7,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { FieldContainer, FieldLabel } from '@keystone-ui/fields'; import { Pill } from '@keystone-ui/pill'; import { Button } from '@keystone-ui/button'; -import { FieldProps } from '@keystone-next/types'; +import { FieldProps } from '@keystone-next/keystone/types'; function useObjectURL(fileData: File | undefined) { let [objectURL, setObjectURL] = useState(undefined); diff --git a/packages/cloudinary/src/views/index.tsx b/packages/cloudinary/src/views/index.tsx index 0e12f549ae4..cb51487a4ec 100644 --- a/packages/cloudinary/src/views/index.tsx +++ b/packages/cloudinary/src/views/index.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { @@ -6,7 +7,7 @@ import { CellComponent, FieldController, FieldControllerConfig, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; import { FieldContainer, FieldLabel } from '@keystone-ui/fields'; import { validateImage } from './Field'; diff --git a/packages/fields-document/CHANGELOG.md b/packages/fields-document/CHANGELOG.md index dae1a7275d3..ceab9e65dbc 100644 --- a/packages/fields-document/CHANGELOG.md +++ b/packages/fields-document/CHANGELOG.md @@ -1,5 +1,36 @@ # @keystone-next/fields-document +## 9.0.0 + +### Major Changes + +- [#6371](https://github.com/keystonejs/keystone/pull/6371) [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/types` to `@keystone-next/keystone/types` + +* [#6426](https://github.com/keystonejs/keystone/pull/6426) [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955) Thanks [@timleslie](https://github.com/timleslie)! - Update the Access Control API. This is a breaking change which impacts the security of all Keystone systems. + + See the [Access Control API](https://keystonejs.com/docs/apis/access-control) for a full description of the new API. + +### Patch Changes + +- [#6367](https://github.com/keystonejs/keystone/pull/6367) [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/admin-ui-utils` to `@keystone-next/keystone/admin-ui/utils` + +* [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +- [#6437](https://github.com/keystonejs/keystone/pull/6437) [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed `isUnique: true` config in fields to `isIndexed: 'unique'` + +* [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed the way the package directory for resolving views is obtained to use `__dirname` rather than `require.resolve('pkg/package.json')` because in Next.js 11 `require.resolve` returns a numeric id instead of the path. + +- [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: + - @keystone-next/keystone@25.0.0 + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/icons@4.0.1 + - @keystone-ui/popover@4.0.3 + - @keystone-ui/tooltip@4.0.2 + ## 8.0.0 ### Major Changes diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index 5484772ac8f..48725c5658b 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -1,7 +1,7 @@ { "name": "@keystone-next/fields-document", "description": "KeystoneJS Document Field Type", - "version": "8.0.0", + "version": "9.0.0", "main": "dist/fields-document.cjs.js", "module": "dist/fields-document.esm.js", "files": [ @@ -22,20 +22,17 @@ "@babel/runtime": "^7.15.3", "@braintree/sanitize-url": "^5.0.2", "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/admin-ui-utils": "^5.0.6", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.1", - "@keystone-ui/icons": "^4.0.0", - "@keystone-ui/popover": "^4.0.1", - "@keystone-ui/tooltip": "^4.0.1", - "@types/react": "^17.0.18", + "@keystone-next/keystone": "^25.0.0", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/icons": "^4.0.1", + "@keystone-ui/popover": "^4.0.3", + "@keystone-ui/tooltip": "^4.0.2", + "@types/react": "^17.0.19", "apply-ref": "^1.0.0", "fp-ts": "^2.11.1", - "graphql": "^15.5.1", + "graphql": "^15.5.2", "io-ts": "^2.2.16", "io-ts-excess": "^1.0.1", "is-hotkey": "^0.2.0", @@ -56,8 +53,8 @@ "devDependencies": { "@testing-library/react": "^12.0.0", "array.prototype.flat": "^1.2.4", - "jest-diff": "^27.0.6", - "pretty-format": "^27.0.6", + "jest-diff": "^27.1.0", + "pretty-format": "^27.1.0", "slate-hyperscript": "^0.60.8" }, "engines": { diff --git a/packages/fields-document/src/DocumentEditor/Toolbar.tsx b/packages/fields-document/src/DocumentEditor/Toolbar.tsx index 45569c44f18..f7853efd4d5 100644 --- a/packages/fields-document/src/DocumentEditor/Toolbar.tsx +++ b/packages/fields-document/src/DocumentEditor/Toolbar.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { diff --git a/packages/fields-document/src/DocumentEditor/alignment.tsx b/packages/fields-document/src/DocumentEditor/alignment.tsx index badce59f2dc..4b4933ad6ec 100644 --- a/packages/fields-document/src/DocumentEditor/alignment.tsx +++ b/packages/fields-document/src/DocumentEditor/alignment.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { AlignLeftIcon } from '@keystone-ui/icons/icons/AlignLeftIcon'; diff --git a/packages/fields-document/src/DocumentEditor/blockquote.test.tsx b/packages/fields-document/src/DocumentEditor/blockquote.test.tsx index 64cf2902ca2..0ae582982c8 100644 --- a/packages/fields-document/src/DocumentEditor/blockquote.test.tsx +++ b/packages/fields-document/src/DocumentEditor/blockquote.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/blockquote.tsx b/packages/fields-document/src/DocumentEditor/blockquote.tsx index 1f327fc294d..4450db99c6f 100644 --- a/packages/fields-document/src/DocumentEditor/blockquote.tsx +++ b/packages/fields-document/src/DocumentEditor/blockquote.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ComponentProps, Fragment, useMemo } from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/code-block.test.tsx b/packages/fields-document/src/DocumentEditor/code-block.test.tsx index 5f94c2fbbff..63a7d9941ee 100644 --- a/packages/fields-document/src/DocumentEditor/code-block.test.tsx +++ b/packages/fields-document/src/DocumentEditor/code-block.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Editor } from 'slate'; import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/code-block.tsx b/packages/fields-document/src/DocumentEditor/code-block.tsx index 32b0a0f9e59..306e17a321f 100644 --- a/packages/fields-document/src/DocumentEditor/code-block.tsx +++ b/packages/fields-document/src/DocumentEditor/code-block.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { Tooltip } from '@keystone-ui/tooltip'; diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx index 44c0e062b3a..21517516f5c 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/document-features-normalization.test.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/document-features-normalization.test.tsx index 205f526ed85..58e6906b1ac 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/document-features-normalization.test.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/document-features-normalization.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Node } from 'slate'; import { component, fields } from '../../component-blocks'; diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/form.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/form.tsx index 51c1c83390d..e7f05d0c663 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/form.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/form.tsx @@ -1,5 +1,5 @@ import { useKeystone } from '@keystone-next/keystone/admin-ui/context'; -import { RelationshipSelect } from '@keystone-next/fields/types/relationship/views/RelationshipSelect'; +import { RelationshipSelect } from '@keystone-next/keystone/fields/types/relationship/views/RelationshipSelect'; import { Stack } from '@keystone-ui/core'; import { FieldContainer, FieldLabel } from '@keystone-ui/fields'; import React, { useState } from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/index.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/index.tsx index 26c04aa7f1e..057a74cf48c 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/index.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Fragment, ReactElement, createContext, useContext, useState, useMemo } from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/insert-break-and-delete.test.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/insert-break-and-delete.test.tsx index d6639e5588f..73eac547d45 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/insert-break-and-delete.test.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/insert-break-and-delete.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { component, fields } from '../../component-blocks'; import { jsx, makeEditor } from '../tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/insertion-and-preview-props.test.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/insertion-and-preview-props.test.tsx index 309f3acb9b7..61a25b733e5 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/insertion-and-preview-props.test.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/insertion-and-preview-props.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Transforms, Element, Editor } from 'slate'; import React from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/normalization.test.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/normalization.test.tsx index 9760a0035e9..ce9216d6932 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/normalization.test.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/normalization.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Transforms } from 'slate'; import { component, fields } from '../../component-blocks'; diff --git a/packages/fields-document/src/DocumentEditor/divider.test.tsx b/packages/fields-document/src/DocumentEditor/divider.test.tsx index c00a027ddac..b4b3b2fc6dd 100644 --- a/packages/fields-document/src/DocumentEditor/divider.test.tsx +++ b/packages/fields-document/src/DocumentEditor/divider.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/heading.test.tsx b/packages/fields-document/src/DocumentEditor/heading.test.tsx index 6226d42f731..c0fb9949496 100644 --- a/packages/fields-document/src/DocumentEditor/heading.test.tsx +++ b/packages/fields-document/src/DocumentEditor/heading.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/heading.tsx b/packages/fields-document/src/DocumentEditor/heading.tsx index ef7eb64bcee..d1de68d5d30 100644 --- a/packages/fields-document/src/DocumentEditor/heading.tsx +++ b/packages/fields-document/src/DocumentEditor/heading.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx } from '@keystone-ui/core'; diff --git a/packages/fields-document/src/DocumentEditor/index.tsx b/packages/fields-document/src/DocumentEditor/index.tsx index f68c89d7fef..c65fbf129db 100644 --- a/packages/fields-document/src/DocumentEditor/index.tsx +++ b/packages/fields-document/src/DocumentEditor/index.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/packages/fields-document/src/DocumentEditor/insert-menu.test.tsx b/packages/fields-document/src/DocumentEditor/insert-menu.test.tsx index 38fedbb6c6d..140bbab7d14 100644 --- a/packages/fields-document/src/DocumentEditor/insert-menu.test.tsx +++ b/packages/fields-document/src/DocumentEditor/insert-menu.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Transforms } from 'slate'; import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/insert-menu.tsx b/packages/fields-document/src/DocumentEditor/insert-menu.tsx index 23ace0bc77f..7a301cea3d2 100644 --- a/packages/fields-document/src/DocumentEditor/insert-menu.tsx +++ b/packages/fields-document/src/DocumentEditor/insert-menu.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, Portal } from '@keystone-ui/core'; import { useControlledPopover } from '@keystone-ui/popover'; diff --git a/packages/fields-document/src/DocumentEditor/layouts.test.tsx b/packages/fields-document/src/DocumentEditor/layouts.test.tsx index add1382bbaf..d3f5095f5b3 100644 --- a/packages/fields-document/src/DocumentEditor/layouts.test.tsx +++ b/packages/fields-document/src/DocumentEditor/layouts.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/layouts.tsx b/packages/fields-document/src/DocumentEditor/layouts.tsx index a99c23c7c4c..51dcd00cec6 100644 --- a/packages/fields-document/src/DocumentEditor/layouts.tsx +++ b/packages/fields-document/src/DocumentEditor/layouts.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { createContext, useContext, useMemo } from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/leaf.tsx b/packages/fields-document/src/DocumentEditor/leaf.tsx index 53fed821cf3..709f8d3f795 100644 --- a/packages/fields-document/src/DocumentEditor/leaf.tsx +++ b/packages/fields-document/src/DocumentEditor/leaf.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/packages/fields-document/src/DocumentEditor/link.tsx b/packages/fields-document/src/DocumentEditor/link.tsx index 45dd1298250..8aed78c1923 100644 --- a/packages/fields-document/src/DocumentEditor/link.tsx +++ b/packages/fields-document/src/DocumentEditor/link.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ReactEditor, RenderElementProps, useFocused, useSelected } from 'slate-react'; diff --git a/packages/fields-document/src/DocumentEditor/lists.test.tsx b/packages/fields-document/src/DocumentEditor/lists.test.tsx index 722c5e06018..cd71a8fb255 100644 --- a/packages/fields-document/src/DocumentEditor/lists.test.tsx +++ b/packages/fields-document/src/DocumentEditor/lists.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { nestList, toggleList } from './lists'; import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/lists.tsx b/packages/fields-document/src/DocumentEditor/lists.tsx index 275e02bf311..059b1ff348e 100644 --- a/packages/fields-document/src/DocumentEditor/lists.tsx +++ b/packages/fields-document/src/DocumentEditor/lists.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ReactNode, forwardRef, useMemo } from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/markdown-link-shortcut.test.tsx b/packages/fields-document/src/DocumentEditor/markdown-link-shortcut.test.tsx index 70944b6f311..53249056b64 100644 --- a/packages/fields-document/src/DocumentEditor/markdown-link-shortcut.test.tsx +++ b/packages/fields-document/src/DocumentEditor/markdown-link-shortcut.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import React from 'react'; import { component, fields } from './component-blocks/api'; diff --git a/packages/fields-document/src/DocumentEditor/marks.test.tsx b/packages/fields-document/src/DocumentEditor/marks.test.tsx index 606c4114961..b123447db3a 100644 --- a/packages/fields-document/src/DocumentEditor/marks.test.tsx +++ b/packages/fields-document/src/DocumentEditor/marks.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { allMarkdownShortcuts } from './marks'; import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/pasting/html-from-other-editors.test.tsx b/packages/fields-document/src/DocumentEditor/pasting/html-from-other-editors.test.tsx index 90db2823582..06e14e18fbc 100644 --- a/packages/fields-document/src/DocumentEditor/pasting/html-from-other-editors.test.tsx +++ b/packages/fields-document/src/DocumentEditor/pasting/html-from-other-editors.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { makeEditor, jsx } from '../tests/utils'; import { MyDataTransfer } from './data-transfer'; diff --git a/packages/fields-document/src/DocumentEditor/pasting/markdown.test.tsx b/packages/fields-document/src/DocumentEditor/pasting/markdown.test.tsx index 60af52a8b01..8d4e99a9938 100644 --- a/packages/fields-document/src/DocumentEditor/pasting/markdown.test.tsx +++ b/packages/fields-document/src/DocumentEditor/pasting/markdown.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { makeEditor, jsx } from '../tests/utils'; import { MyDataTransfer } from './data-transfer'; diff --git a/packages/fields-document/src/DocumentEditor/primitives/inline-dialog.tsx b/packages/fields-document/src/DocumentEditor/primitives/inline-dialog.tsx index 00e1fb71a05..8078e4983ba 100644 --- a/packages/fields-document/src/DocumentEditor/primitives/inline-dialog.tsx +++ b/packages/fields-document/src/DocumentEditor/primitives/inline-dialog.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/packages/fields-document/src/DocumentEditor/primitives/toolbar.tsx b/packages/fields-document/src/DocumentEditor/primitives/toolbar.tsx index f753b1edb41..2ffb83e715d 100644 --- a/packages/fields-document/src/DocumentEditor/primitives/toolbar.tsx +++ b/packages/fields-document/src/DocumentEditor/primitives/toolbar.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { ButtonHTMLAttributes, HTMLAttributes, createContext, useContext, ReactNode } from 'react'; diff --git a/packages/fields-document/src/DocumentEditor/relationship.tsx b/packages/fields-document/src/DocumentEditor/relationship.tsx index 481e6f430e4..3ef4b1a18a7 100644 --- a/packages/fields-document/src/DocumentEditor/relationship.tsx +++ b/packages/fields-document/src/DocumentEditor/relationship.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { createContext, Fragment, useContext } from 'react'; @@ -6,7 +7,7 @@ import { Transforms, Editor } from 'slate'; import { jsx } from '@keystone-ui/core'; import { useKeystone } from '@keystone-next/keystone/admin-ui/context'; -import { RelationshipSelect } from '@keystone-next/fields/types/relationship/views/RelationshipSelect'; +import { RelationshipSelect } from '@keystone-next/keystone/fields/types/relationship/views/RelationshipSelect'; import { ToolbarButton } from './primitives'; import { useStaticEditor } from './utils'; diff --git a/packages/fields-document/src/DocumentEditor/render-element.tsx b/packages/fields-document/src/DocumentEditor/render-element.tsx index a5f03aaa201..563c1b7b096 100644 --- a/packages/fields-document/src/DocumentEditor/render-element.tsx +++ b/packages/fields-document/src/DocumentEditor/render-element.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/packages/fields-document/src/DocumentEditor/shortcuts.test.tsx b/packages/fields-document/src/DocumentEditor/shortcuts.test.tsx index 093277322b3..05f8fbcba0a 100644 --- a/packages/fields-document/src/DocumentEditor/shortcuts.test.tsx +++ b/packages/fields-document/src/DocumentEditor/shortcuts.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { shortcuts } from './shortcuts'; import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/soft-breaks.test.tsx b/packages/fields-document/src/DocumentEditor/soft-breaks.test.tsx index 5f88bd6e32f..c2e228056a0 100644 --- a/packages/fields-document/src/DocumentEditor/soft-breaks.test.tsx +++ b/packages/fields-document/src/DocumentEditor/soft-breaks.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Editor } from 'slate'; import { jsx, makeEditor } from './tests/utils'; diff --git a/packages/fields-document/src/DocumentEditor/tests/test-utils.test.tsx b/packages/fields-document/src/DocumentEditor/tests/test-utils.test.tsx index bf9b09512e7..ec0c266ac7a 100644 --- a/packages/fields-document/src/DocumentEditor/tests/test-utils.test.tsx +++ b/packages/fields-document/src/DocumentEditor/tests/test-utils.test.tsx @@ -1,4 +1,5 @@ /** @jest-environment jsdom */ +/** @jsxRuntime classic */ /** @jsx jsx */ import { Editor } from 'slate'; import { jsx, makeEditor } from './utils'; diff --git a/packages/fields-document/src/index.ts b/packages/fields-document/src/index.ts index 9fbd1819af0..0f79732dbf8 100644 --- a/packages/fields-document/src/index.ts +++ b/packages/fields-document/src/index.ts @@ -4,10 +4,10 @@ import { CommonFieldConfig, FieldTypeFunc, jsonFieldTypePolyfilledForSQLite, - schema, + graphql, JSONValue, FieldDefaultValue, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; import { Relationships } from './DocumentEditor/relationship'; import { ComponentBlock } from './component-blocks'; import { DocumentFeatures } from './views'; @@ -79,10 +79,7 @@ export type DocumentFieldConfig[], TGeneratedListTypes>; }; -const views = path.join( - path.dirname(require.resolve('@keystone-next/fields-document/package.json')), - 'views' -); +const views = path.join(path.dirname(__dirname), 'views'); export const document = ({ @@ -112,28 +109,28 @@ export const document = return validateAndNormalizeDocument(data, documentFeatures, componentBlocks, relationships); }; - if ((config as any).isUnique) { - throw Error('isUnique is not a supported option for field type document'); + if ((config as any).isIndexed === 'unique') { + throw Error("isIndexed: 'unique' is not a supported option for field type document"); } return jsonFieldTypePolyfilledForSQLite(meta.provider, { ...config, input: { - create: { arg: schema.arg({ type: schema.JSON }), resolve: inputResolver }, - update: { arg: schema.arg({ type: schema.JSON }), resolve: inputResolver }, + create: { arg: graphql.arg({ type: graphql.JSON }), resolve: inputResolver }, + update: { arg: graphql.arg({ type: graphql.JSON }), resolve: inputResolver }, }, - output: schema.field({ - type: schema.object<{ document: JSONValue }>()({ + output: graphql.field({ + type: graphql.object<{ document: JSONValue }>()({ name: `${meta.listKey}_${meta.fieldKey}_DocumentField`, fields: { - document: schema.field({ + document: graphql.field({ args: { - hydrateRelationships: schema.arg({ - type: schema.nonNull(schema.Boolean), + hydrateRelationships: graphql.arg({ + type: graphql.nonNull(graphql.Boolean), defaultValue: false, }), }, - type: schema.nonNull(schema.JSON), + type: graphql.nonNull(graphql.JSON), resolve({ document }, { hydrateRelationships }, context) { return hydrateRelationships ? addRelationshipData( diff --git a/packages/fields-document/src/relationship-data.tsx b/packages/fields-document/src/relationship-data.tsx index ede96091c09..2c870dc97fd 100644 --- a/packages/fields-document/src/relationship-data.tsx +++ b/packages/fields-document/src/relationship-data.tsx @@ -1,4 +1,8 @@ -import { BaseGeneratedListTypes, GqlNames, KeystoneGraphQLAPI } from '@keystone-next/types'; +import { + BaseGeneratedListTypes, + GqlNames, + KeystoneGraphQLAPI, +} from '@keystone-next/keystone/types'; import { Descendant } from 'slate'; import { GraphQLSchema, executeSync, parse } from 'graphql'; import weakMemoize from '@emotion/weak-memoize'; @@ -55,22 +59,20 @@ export function addRelationshipData( }}}`, variables: { id }, }); - } catch (err) { - if (err.message === 'You do not have access to this resource') { - // If we're unable to find the item (e.g. we have a dangling reference), or access was denied - // then simply return { id } and leave `label` and `data` undefined. - const r = JSON.stringify(relationship); + if (val.item === null) { if (!process.env.TEST_ADAPTER) { + // If we're unable to find the item (e.g. we have a dangling reference), or access was denied + // then simply return { id } and leave `label` and `data` undefined. + const r = JSON.stringify(relationship); console.error(`Unable to fetch relationship data: relationship: ${r}, id: ${id} `); - console.error(err); } return { id }; - } else { - // Other types of errors indicate something wrong with either the system or the - // configuration (e.g. a bad selection field) and they should be surfaced as a - // GraphQL error. - throw err; } + } catch (err) { + // Errors indicate something wrong with either the system or the + // configuration (e.g. a bad selection field) and they should be surfaced as a + // GraphQL error. + throw err; } return { id, diff --git a/packages/fields-document/src/tests/test-fixtures.ts b/packages/fields-document/src/tests/test-fixtures.ts index e6a715fc601..3b96abd92b1 100644 --- a/packages/fields-document/src/tests/test-fixtures.ts +++ b/packages/fields-document/src/tests/test-fixtures.ts @@ -1,4 +1,3 @@ -import { text } from '@keystone-next/fields'; import { document } from '..'; export const name = 'Document'; @@ -17,7 +16,7 @@ export const supportsUnique = false; export const fieldName = 'content'; export const subfieldName = 'document'; -export const getTestFields = () => ({ name: text(), content: document() }); +export const getTestFields = () => ({ content: document() }); export const initItems = () => { return [ diff --git a/packages/fields-document/src/validation.test.tsx b/packages/fields-document/src/validation.test.tsx index 101f67a126a..33f239054c3 100644 --- a/packages/fields-document/src/validation.test.tsx +++ b/packages/fields-document/src/validation.test.tsx @@ -1,3 +1,4 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ import { component, ComponentBlock, fields } from './DocumentEditor/component-blocks/api'; import { Relationships } from './DocumentEditor/relationship'; diff --git a/packages/fields-document/src/views.tsx b/packages/fields-document/src/views.tsx index 94cb55a74f4..4f158b4a9aa 100644 --- a/packages/fields-document/src/views.tsx +++ b/packages/fields-document/src/views.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { FieldContainer, FieldLabel } from '@keystone-ui/fields'; @@ -10,7 +11,7 @@ import { FieldController, FieldControllerConfig, FieldProps, -} from '@keystone-next/types'; +} from '@keystone-next/keystone/types'; import weakMemoize from '@emotion/weak-memoize'; import { DocumentEditor } from './DocumentEditor'; import { ComponentBlock } from './component-blocks'; diff --git a/packages/fields/CHANGELOG.md b/packages/fields/CHANGELOG.md index cafa88f5de0..756a557b2e3 100644 --- a/packages/fields/CHANGELOG.md +++ b/packages/fields/CHANGELOG.md @@ -1,5 +1,11 @@ # @keystone-next/fields +## 15.0.0 + +### Major Changes + +- [#6362](https://github.com/keystonejs/keystone/pull/6362) [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/fields` to `@keystone-next/keystone/fields` + ## 14.0.0 ### Major Changes diff --git a/packages/fields/README.md b/packages/fields/README.md index a885e826022..eaa05fed160 100644 --- a/packages/fields/README.md +++ b/packages/fields/README.md @@ -1,5 +1,7 @@ # @keystone-next/fields +The exports of this package have been moved to `@keystone-next/keystone/fields`. + Keystone-next is a preview release of the next version of Keystone. Please visit for full details. For updates, [follow @keystonejs on Twitter](https://twitter.com/keystonejs) and [join us in Slack](https://community.keystonejs.com/). diff --git a/packages/fields/package.json b/packages/fields/package.json index 27336167293..a4a158f3997 100644 --- a/packages/fields/package.json +++ b/packages/fields/package.json @@ -1,55 +1,11 @@ { "name": "@keystone-next/fields", - "version": "14.0.0", + "version": "15.0.0", "license": "MIT", "main": "dist/fields.cjs.js", "module": "dist/fields.esm.js", - "devDependencies": { - "@types/bytes": "^3.1.1", - "fs-extra": "^10.0.0", - "graphql": "^15.5.1", - "mime": "^2.5.2" - }, - "dependencies": { - "@babel/runtime": "^7.15.3", - "@keystone-next/admin-ui-utils": "^5.0.6", - "@keystone-next/keystone": "^24.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-next/utils": "^1.0.4", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.2", - "@keystone-ui/icons": "^4.0.0", - "@keystone-ui/loading": "^4.0.0", - "@keystone-ui/modals": "^4.0.0", - "@keystone-ui/pill": "^5.0.0", - "@keystone-ui/segmented-control": "^4.0.2", - "@keystone-ui/toast": "^4.0.2", - "@keystone-ui/tooltip": "^4.0.1", - "@types/bcryptjs": "^2.4.2", - "@types/react": "^17.0.18", - "bcryptjs": "^2.4.3", - "bytes": "^3.1.0", - "copy-to-clipboard": "^3.3.1", - "date-fns": "^2.23.0", - "decimal.js": "10.3.1", - "dumb-passwords": "^0.2.1", - "fast-deep-equal": "^3.1.3", - "graphql-upload": "^12.0.0", - "inflection": "^1.13.1", - "intersection-observer": "^0.12.0", - "react": "^17.0.2", - "uuid": "^8.3.2" - }, "engines": { "node": "^12.20 || >= 14.13" }, - "preconstruct": { - "entrypoints": [ - "index.ts", - "types/*/views/index.tsx", - "types/relationship/views/RelationshipSelect.tsx" - ] - }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/fields" } diff --git a/packages/fields/src/get-index-type.ts b/packages/fields/src/get-index-type.ts deleted file mode 100644 index de1bfe66340..00000000000 --- a/packages/fields/src/get-index-type.ts +++ /dev/null @@ -1,12 +0,0 @@ -export function getIndexType({ - isIndexed, - isUnique, -}: { - isIndexed?: boolean; - isUnique?: boolean; -}): undefined | 'index' | 'unique' { - if (isUnique && isIndexed) { - throw new Error('Only one of isUnique and isIndexed can be passed to field types'); - } - return isIndexed ? 'index' : isUnique ? 'unique' : undefined; -} diff --git a/packages/fields/src/index.ts b/packages/fields/src/index.ts index 70ac5f483ed..bf7cc1b7b46 100644 --- a/packages/fields/src/index.ts +++ b/packages/fields/src/index.ts @@ -1,14 +1,5 @@ -export { autoIncrement } from './types/autoIncrement'; -export { checkbox } from './types/checkbox'; -export { decimal } from './types/decimal'; -export { file } from './types/file'; -export { float } from './types/float'; -export { integer } from './types/integer'; -export { image } from './types/image'; -export { json } from './types/json'; -export { password } from './types/password'; -export { relationship } from './types/relationship'; -export { select } from './types/select'; -export { text } from './types/text'; -export { timestamp } from './types/timestamp'; -export { virtual } from './types/virtual'; +throw new Error( + '`@keystone-next/fields` has been moved to `@keystone-next/keystone/fields`, please import from there instead.' +); + +export {}; diff --git a/packages/fields/src/resolve-view.ts b/packages/fields/src/resolve-view.ts deleted file mode 100644 index b6bf2b52839..00000000000 --- a/packages/fields/src/resolve-view.ts +++ /dev/null @@ -1,5 +0,0 @@ -import path from 'path'; - -const pkgDir = path.dirname(require.resolve('@keystone-next/fields/package.json')); - -export const resolveView = (pathname: string) => path.join(pkgDir, 'types', pathname); diff --git a/packages/fields/src/types/file/README.md b/packages/fields/src/types/file/README.md deleted file mode 100644 index 197beb241b8..00000000000 --- a/packages/fields/src/types/file/README.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# File - -Support files hosted in a range of different contexts, e.g. in the local filesystem, or on a cloud based file server. - -## Usage - -```js -const { File } = require('@keystone-next/fields-legacy'); -const { LocalFileAdapter } = require('@keystone-next/file-adapters-legacy'); - -const fileAdapter = new LocalFileAdapter({ - /*...config */ -}); - -keystone.createList('Applicant', { - fields: { - file: { - type: File, - adapter: fileAdapter, - isRequired: true, - }, - }, -}); -``` - -### Config - -| Option | Type | Default | Description | -| ------------ | --------- | -------- | --------------------------------------------------------------------------------------- | -| `adapter` | `Object` | Required | See the [File Adapters](/packages/file-adapters/README.md) page for available adapters. | -| `isRequired` | `Boolean` | `false` | Does this field require a value? | diff --git a/packages/fields/types/checkbox/views/package.json b/packages/fields/types/checkbox/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/checkbox/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/decimal/views/package.json b/packages/fields/types/decimal/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/decimal/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/file/views/package.json b/packages/fields/types/file/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/file/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/float/views/package.json b/packages/fields/types/float/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/float/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/image/views/package.json b/packages/fields/types/image/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/image/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/integer/views/package.json b/packages/fields/types/integer/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/integer/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/json/views/package.json b/packages/fields/types/json/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/json/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/password/views/package.json b/packages/fields/types/password/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/password/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/relationship/views/RelationshipSelect/package.json b/packages/fields/types/relationship/views/RelationshipSelect/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/relationship/views/RelationshipSelect/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/relationship/views/package.json b/packages/fields/types/relationship/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/relationship/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/select/views/package.json b/packages/fields/types/select/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/select/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/text/views/package.json b/packages/fields/types/text/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/text/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/timestamp/views/package.json b/packages/fields/types/timestamp/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/timestamp/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/fields/types/virtual/views/package.json b/packages/fields/types/virtual/views/package.json deleted file mode 100644 index 0a2b32cebb5..00000000000 --- a/packages/fields/types/virtual/views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js" -} diff --git a/packages/keystone/CHANGELOG.md b/packages/keystone/CHANGELOG.md index 718e85be1cd..eb764713980 100644 --- a/packages/keystone/CHANGELOG.md +++ b/packages/keystone/CHANGELOG.md @@ -1,5 +1,110 @@ # @keystone-next/keystone +## 25.0.0 + +### Major Changes + +- [#6377](https://github.com/keystonejs/keystone/pull/6377) [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved exports of `@keystone-next/keystone` to `@keystone-next/keystone/system` + +* [#6323](https://github.com/keystonejs/keystone/pull/6323) [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed unused legacy filter code + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated to Next.js 11. If you were using a custom Babel config, it will no longer be respected because of changes in Next.js. + +* [#6393](https://github.com/keystonejs/keystone/pull/6393) [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated `@graphql-ts/schema` to `0.3.0` and moved the `schema` export to `@keystone-next/keystone` entrypoint and renamed it to `graphql`. `bindSchemaAPIToContext` on the `graphql` export has also been renamed to `bindGraphQLSchemaAPIToContext`. + +- [#6426](https://github.com/keystonejs/keystone/pull/6426) [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955) Thanks [@timleslie](https://github.com/timleslie)! - Update the Access Control API. This is a breaking change which impacts the security of all Keystone systems. + + See the [Access Control API](https://keystonejs.com/docs/apis/access-control) for a full description of the new API. + +* [#6420](https://github.com/keystonejs/keystone/pull/6420) [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6) Thanks [@timleslie](https://github.com/timleslie)! - Added the config option `graphql.omit` to list and field level configuration to control which types and operations are excluded from the GraphQL API. The use of a static `false` value in access control definitions no longer excludes operations from the GraphQL API. + +- [#6455](https://github.com/keystonejs/keystone/pull/6455) [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a) Thanks [@timleslie](https://github.com/timleslie)! - The `fieldPath` argument to field hooks has been renamed to `fieldKey`. This makes the naming consistent with the Access Control APIs. + +* [#6463](https://github.com/keystonejs/keystone/pull/6463) [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908) Thanks [@JedWatson](https://github.com/JedWatson)! - The GraphQL API endpoint now starts up significantly faster in Dev. + + To facilitate this, `createExpressServer` no longer includes the step of creating the Admin UI Middleware, which changes its signature. `createAdminUIMiddleware` is now also exported from `@keystone-next/keystone/system`. + +- [#6437](https://github.com/keystonejs/keystone/pull/6437) [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed `isUnique: true` config in fields to `isIndexed: 'unique'` + +* [#6420](https://github.com/keystonejs/keystone/pull/6420) [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6) Thanks [@timleslie](https://github.com/timleslie)! - Filtering and ordering is no longer enabled by default, as they have the potential to expose data which would otherwise be protected by access control. To enable filtering and ordering you can set `isFilterable: true` and `isOrderable: true` on specific fields, or set `defaultIsFilterable: true` and `defaultIsOrderable: true` at the list level. + +- [#6378](https://github.com/keystonejs/keystone/pull/6378) [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved exports of `@keystone-next/keystone/schema` to `@keystone-next/keystone` + +### Minor Changes + +- [#6403](https://github.com/keystonejs/keystone/pull/6403) [`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951) Thanks [@timleslie](https://github.com/timleslie)! - Added the experimental config option `config.experimental.contextInitialisedLists`, which adds the internal data structure `experimental.initialisedLists` to the `context` object. This is a temporary addition to the API which will be removed in a future release once a more controlled API is available. It should be used with caution, as it will contain breaking change in `patch` level releases. + +* [#6371](https://github.com/keystonejs/keystone/pull/6371) [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/types` to `@keystone-next/keystone/types` + +- [#6367](https://github.com/keystonejs/keystone/pull/6367) [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/admin-ui-utils` to `@keystone-next/keystone/admin-ui/utils` + +* [#6361](https://github.com/keystonejs/keystone/pull/6361) [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved exports of `@keystone-next/testing` to `@keystone-next/keystone/testing` + +- [#6368](https://github.com/keystonejs/keystone/pull/6368) [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/utils` to `@keystone-next/keystone/fields/types/image/utils` for image ref related utilities and `@keystone-next/keystone/fields/types/file/utils` for file ref related utilities. + +* [#6458](https://github.com/keystonejs/keystone/pull/6458) [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555) Thanks [@timleslie](https://github.com/timleslie)! - Added the config option `config.graphql.path` to configure the endpoint of the GraphQL API (default `'/api/graphql'`). + +- [#6467](https://github.com/keystonejs/keystone/pull/6467) [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed) Thanks [@JedWatson](https://github.com/JedWatson)! - Add extendExpressApp config option for configuring the express app that Keystone creates + +* [#6459](https://github.com/keystonejs/keystone/pull/6459) [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47) Thanks [@timleslie](https://github.com/timleslie)! - Updated Navigation component to show docs and playground links irrespective of authentication. + +- [#6362](https://github.com/keystonejs/keystone/pull/6362) [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/fields` to `@keystone-next/keystone/fields` + +### Patch Changes + +- [#6390](https://github.com/keystonejs/keystone/pull/6390) [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Improved performance of create item modal with many fields + +* [#6385](https://github.com/keystonejs/keystone/pull/6385) [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da) Thanks [@gautamsi](https://github.com/gautamsi)! - Fixed issue in Relationship field display mode 'count'. It was using `_fieldnameMeta.count` instead of `fieldnameCount` + +- [#6422](https://github.com/keystonejs/keystone/pull/6422) [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504) Thanks [@timleslie](https://github.com/timleslie)! - Made cosmetic changes to the Admin UI code. No functional changes. + +* [#6453](https://github.com/keystonejs/keystone/pull/6453) [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Dashboard cards now enclosed in unordered list, for clearer semantics. + +- [#6397](https://github.com/keystonejs/keystone/pull/6397) [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added a comment in the `schema.prisma` and `schema.graphql` files explaining that they're generated and should not be modified manually. + +* [#6391](https://github.com/keystonejs/keystone/pull/6391) [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41) Thanks [@bladey](https://github.com/bladey)! - Adds support for `introspection` in the Apollo Server config. Introspection enables you to query a GraphQL server for information about the underlying schema. If the playground is enabled then introspection is automatically enabled - unless specifically disabled. + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usages of `jsx` from `@keystone-ui/core` to explicitly use `/** @jsxRuntime classic */` + +* [#6392](https://github.com/keystonejs/keystone/pull/6392) [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed negative `take` values above the list's `graphql.queryLimits.maxResults` not causing an error before getting the values from the database. + +- [#6381](https://github.com/keystonejs/keystone/pull/6381) [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed error from prisma when using `.keystone/api` from `generateNodeAPI` in a API route (`admin/pages/api/*`) + +* [#6429](https://github.com/keystonejs/keystone/pull/6429) [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2) Thanks [@timleslie](https://github.com/timleslie)! - Update adminMeta `fieldMode` resolvers to respect `graphql.omit` configuration. + +- [#6414](https://github.com/keystonejs/keystone/pull/6414) [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed the way the package directory for resolving views is obtained to use `__dirname` rather than `require.resolve('pkg/package.json')` because in Next.js 11 `require.resolve` returns a numeric id instead of the path. + +* [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. + +- [#6412](https://github.com/keystonejs/keystone/pull/6412) [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Merged aria-description text for dialogs on list view in Admin UI into their respective aria-labels. + +* [#6462](https://github.com/keystonejs/keystone/pull/6462) [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixed crashing the process when createContext() fails for Admin UI requests + +- [#6354](https://github.com/keystonejs/keystone/pull/6354) [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed Listview checkbox bug in a better way. + +* [#6433](https://github.com/keystonejs/keystone/pull/6433) [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248) Thanks [@renovate](https://github.com/apps/renovate)! - Updated Prisma dependencies to `2.30.2`. + +* Updated dependencies [[`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c)]: + - @keystone-ui/button@5.0.1 + - @keystone-ui/core@3.2.0 + - @keystone-ui/fields@4.1.3 + - @keystone-ui/icons@4.0.1 + - @keystone-ui/loading@4.0.1 + - @keystone-ui/modals@4.0.1 + - @keystone-ui/notice@4.0.2 + - @keystone-ui/options@4.0.2 + - @keystone-ui/pill@5.0.1 + - @keystone-ui/popover@4.0.3 + - @keystone-ui/segmented-control@4.0.3 + - @keystone-ui/toast@4.0.3 + - @keystone-ui/tooltip@4.0.2 + +## 24.0.1 + +### Patch Changes + +- [#6350](https://github.com/keystonejs/keystone/pull/6350) [`9ca1c41cd`](https://github.com/keystonejs/keystone/commit/9ca1c41cd6cc34b4cf4393abfbe2e4b43a275401) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed delete toast not leveraging labelField property. + ## 24.0.0 ### Major Changes diff --git a/packages/keystone/admin-ui/utils/package.json b/packages/keystone/admin-ui/utils/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/admin-ui/utils/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/package.json b/packages/keystone/fields/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/checkbox/views/package.json b/packages/keystone/fields/types/checkbox/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/checkbox/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/decimal/views/package.json b/packages/keystone/fields/types/decimal/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/decimal/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/file/utils/package.json b/packages/keystone/fields/types/file/utils/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/file/utils/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/file/views/package.json b/packages/keystone/fields/types/file/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/file/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/float/views/package.json b/packages/keystone/fields/types/float/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/float/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/image/utils/package.json b/packages/keystone/fields/types/image/utils/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/image/utils/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/image/views/package.json b/packages/keystone/fields/types/image/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/image/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/integer/views/package.json b/packages/keystone/fields/types/integer/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/integer/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/json/views/package.json b/packages/keystone/fields/types/json/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/json/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/password/views/package.json b/packages/keystone/fields/types/password/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/password/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/relationship/views/RelationshipSelect/package.json b/packages/keystone/fields/types/relationship/views/RelationshipSelect/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/relationship/views/RelationshipSelect/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/relationship/views/package.json b/packages/keystone/fields/types/relationship/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/relationship/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/select/views/package.json b/packages/keystone/fields/types/select/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/select/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/text/views/package.json b/packages/keystone/fields/types/text/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/text/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/timestamp/views/package.json b/packages/keystone/fields/types/timestamp/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/timestamp/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/fields/types/virtual/views/package.json b/packages/keystone/fields/types/virtual/views/package.json new file mode 100644 index 00000000000..6cbbe144d0c --- /dev/null +++ b/packages/keystone/fields/types/virtual/views/package.json @@ -0,0 +1,4 @@ +{ + "main": "dist/keystone.cjs.js", + "module": "dist/keystone.esm.js" +} diff --git a/packages/keystone/package.json b/packages/keystone/package.json index d2be3d4829e..1136af97c82 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/keystone", - "version": "24.0.0", + "version": "25.0.0", "license": "MIT", "main": "dist/keystone.cjs.js", "module": "dist/keystone.esm.js", @@ -16,52 +16,59 @@ "session", "dist", "static", - "admin-ui" + "admin-ui", + "testing", + "fields", + "types", + "system" ], "bin": { "keystone-next": "bin/cli.js" }, "dependencies": { - "@apollo/client": "^3.4.8", + "@apollo/client": "^3.4.10", "@babel/core": "^7.15.0", "@babel/plugin-transform-modules-commonjs": "^7.15.0", "@babel/runtime": "^7.15.3", "@emotion/hash": "^0.8.0", - "@graphql-tools/schema": "^8.1.1", + "@emotion/weak-memoize": "^0.2.5", + "@graphql-tools/schema": "^8.2.0", + "@graphql-ts/schema": "0.3.0", "@hapi/iron": "^6.0.0", - "@keystone-next/admin-ui-utils": "^5.0.6", - "@keystone-next/fields": "^14.0.0", - "@keystone-next/types": "^24.0.0", - "@keystone-next/utils": "^1.0.4", - "@keystone-ui/button": "^5.0.0", - "@keystone-ui/core": "^3.1.1", - "@keystone-ui/fields": "^4.1.2", - "@keystone-ui/icons": "^4.0.0", - "@keystone-ui/loading": "^4.0.0", - "@keystone-ui/modals": "^4.0.0", - "@keystone-ui/notice": "^4.0.1", - "@keystone-ui/options": "^4.0.1", - "@keystone-ui/pill": "^5.0.0", - "@keystone-ui/popover": "^4.0.2", - "@keystone-ui/toast": "^4.0.2", - "@keystone-ui/tooltip": "^4.0.1", + "@keystone-ui/button": "^5.0.1", + "@keystone-ui/core": "^3.2.0", + "@keystone-ui/fields": "^4.1.3", + "@keystone-ui/icons": "^4.0.1", + "@keystone-ui/loading": "^4.0.1", + "@keystone-ui/modals": "^4.0.1", + "@keystone-ui/notice": "^4.0.2", + "@keystone-ui/options": "^4.0.2", + "@keystone-ui/pill": "^5.0.1", + "@keystone-ui/popover": "^4.0.3", + "@keystone-ui/segmented-control": "^4.0.3", + "@keystone-ui/toast": "^4.0.3", + "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@prisma/client": "2.29.1", - "@prisma/migrate": "2.29.1", - "@prisma/sdk": "2.29.1", + "@prisma/client": "2.30.2", + "@prisma/migrate": "2.30.2", + "@prisma/sdk": "2.30.2", "@sindresorhus/slugify": "^1.1.2", "@types/apollo-upload-client": "14.1.0", "@types/babel__core": "^7.1.15", + "@types/bcryptjs": "^2.4.2", "@types/cookie": "^0.4.1", "@types/express": "^4.17.13", "@types/form-data": "2.5.0", "@types/fs-extra": "^9.0.12", - "@types/graphql-upload": "^8.0.6", + "@types/graphql-upload": "^8.0.7", + "@types/inflection": "^1.5.28", "@types/node-fetch": "^2.5.12", "@types/pluralize": "^0.0.29", "@types/prettier": "^2.3.2", "@types/prompts": "^2.0.14", + "@types/react": "^17.0.19", "@types/source-map-support": "^0.5.4", + "@types/supertest": "^2.0.11", "@types/uid-safe": "^2.1.2", "@types/uuid": "^8.3.1", "apollo-server-errors": "^2.5.0", @@ -69,11 +76,17 @@ "apollo-server-micro": "^2.25.2", "apollo-server-types": "^0.9.0", "apollo-upload-client": "^16.0.0", + "bcryptjs": "^2.4.3", + "bytes": "^3.1.0", "chalk": "^4.1.2", "clipboard-copy": "^4.0.1", "cookie": "^0.4.1", + "copy-to-clipboard": "^3.3.1", "cors": "^2.8.5", "cuid": "^2.1.8", + "date-fns": "^2.23.0", + "decimal.js": "10.3.1", + "dumb-passwords": "^0.2.1", "execa": "^5.1.1", "express": "^4.17.1", "fast-deep-equal": "^3.1.3", @@ -81,34 +94,40 @@ "filenamify": "^4.3.0", "form-data": "4.0.0", "fs-extra": "^10.0.0", - "graphql": "^15.5.1", + "graphql": "^15.5.2", "graphql-type-json": "^0.3.2", "graphql-upload": "^12.0.0", "image-size": "^1.0.0", "image-type": "^4.1.0", + "inflection": "^1.13.1", + "intersection-observer": "^0.12.0", + "memoize-one": "^5.2.1", "meow": "^9.0.0", - "next": "^10.2.3", + "next": "^11.1.0", "node-fetch": "^2.6.1", "object-hash": "^2.2.0", "p-limit": "^2.3.0", "pirates": "^4.0.1", "pluralize": "^8.0.0", "prettier": "^2.3.2", - "prisma": "2.29.1", + "prisma": "2.30.2", "prompts": "^2.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", "resolve": "^1.20.0", "source-map-support": "^0.5.19", - "typescript": "^4.3.5", + "supertest": "^6.1.6", + "typescript": "^4.4.2", "uid-safe": "^2.1.5", "uuid": "^8.3.2" }, "devDependencies": { - "@testing-library/dom": "^8.1.0", + "@testing-library/dom": "^8.2.0", "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", + "@types/bytes": "^3.1.1", "fixturez": "^1.1.0", + "mime": "^2.5.2", "outdent": "^0.8.0", "string-argv": "^0.3.1", "strip-ansi": "^6.0.0" @@ -119,12 +138,14 @@ "preconstruct": { "entrypoints": [ "index.ts", + "system.ts", "next.ts", "___internal-do-not-use-will-break-in-patch/{node-api,next-graphql}.ts", "___internal-do-not-use-will-break-in-patch/admin-ui/pages/*/index.tsx", "___internal-do-not-use-will-break-in-patch/admin-ui/{next-config.ts,id-field-view.tsx}", "artifacts.ts", "migrations.ts", + "testing.ts", "schema/index.ts", "session/index.ts", "scripts/index.ts", @@ -132,7 +153,13 @@ "admin-ui/apollo.tsx", "admin-ui/context.tsx", "admin-ui/router.tsx", - "admin-ui/image.tsx" + "admin-ui/image.tsx", + "admin-ui/utils/index.ts", + "fields/index.ts", + "fields/types/*/views/index.tsx", + "fields/types/relationship/views/RelationshipSelect.tsx", + "fields/types/{image,file}/utils.ts", + "types/index.ts" ] }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/keystone" diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx index cba2c258087..709ffc98bca 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx } from '@keystone-ui/core'; import { FieldContainer, FieldLabel, TextInput } from '@keystone-ui/fields'; @@ -8,7 +9,7 @@ import { FieldController, FieldControllerConfig, IdFieldConfig, -} from '@keystone-next/types'; +} from '../../types'; import { CellLink, CellContainer } from '../../admin-ui/components'; export const Field = () => null; @@ -75,38 +76,14 @@ export const controller = ( return `${label.toLowerCase()}: ${renderedValue}`; }, types: { - is: { - label: 'Is exactly', - initialValue: '', - }, - not: { - label: 'Is not exactly', - initialValue: '', - }, - gt: { - label: 'Is greater than', - initialValue: '', - }, - lt: { - label: 'Is less than', - initialValue: '', - }, - gte: { - label: 'Is greater than or equal to', - initialValue: '', - }, - lte: { - label: 'Is less than or equal to', - initialValue: '', - }, - in: { - label: 'Is one of', - initialValue: '', - }, - not_in: { - label: 'Is not one of', - initialValue: '', - }, + is: { label: 'Is exactly', initialValue: '' }, + not: { label: 'Is not exactly', initialValue: '' }, + gt: { label: 'Is greater than', initialValue: '' }, + lt: { label: 'Is less than', initialValue: '' }, + gte: { label: 'Is greater than or equal to', initialValue: '' }, + lte: { label: 'Is less than or equal to', initialValue: '' }, + in: { label: 'Is one of', initialValue: '' }, + not_in: { label: 'Is not one of', initialValue: '' }, }, }, }; diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts index db51999f8e2..5a8c4cc710b 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/next-config.ts @@ -6,6 +6,9 @@ export const config = withPreconstruct({ typescript: { ignoreBuildErrors: true, }, + eslint: { + ignoreDuringBuilds: true, + }, webpack(config: any, { isServer }: any) { config.resolve.alias = { ...config.resolve.alias, @@ -18,8 +21,8 @@ export const config = withPreconstruct({ if (isServer) { config.externals = [ ...config.externals, - /@keystone-next\/keystone(?!\/___internal-do-not-use-will-break-in-patch\/admin-ui\/id-field-view)/, - /@keystone-next\/types/, + /@keystone-next\/keystone(?!\/___internal-do-not-use-will-break-in-patch\/admin-ui\/id-field-view|\/fields\/types\/[^\/]+\/views)/, + '.prisma/client', ]; } return config; diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx index b15dc85f40b..0b50aa8ee90 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Core } from '@keystone-ui/core'; import { AppProps } from 'next/app'; import { DocumentNode } from 'graphql'; -import { AdminConfig, FieldViews } from '@keystone-next/types'; +import { AdminConfig, FieldViews } from '../../../../types'; import { ErrorBoundary } from '../../../../admin-ui/components'; import { KeystoneProvider } from '../../../../admin-ui/context'; @@ -11,6 +11,7 @@ type AppConfig = { adminMetaHash: string; fieldViews: FieldViews; lazyMetadataQuery: DocumentNode; + apiPath: string; }; export const getApp = diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.tsx index a7d1c4830f3..5a16e51b12e 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage/index.tsx @@ -1,13 +1,14 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { ButtonHTMLAttributes, useMemo, useState } from 'react'; import { Center, Inline, Heading, VisuallyHidden, jsx, useTheme } from '@keystone-ui/core'; -import { makeDataGetter } from '@keystone-next/admin-ui-utils'; import { PlusIcon } from '@keystone-ui/icons/icons/PlusIcon'; import { DrawerController } from '@keystone-ui/modals'; import { LoadingDots } from '@keystone-ui/loading'; +import { makeDataGetter } from '../../../../admin-ui/utils'; import { CreateItemDrawer } from '../../../../admin-ui/components/CreateItemDrawer'; import { PageContainer, HEADER_HEIGHT } from '../../../../admin-ui/components/PageContainer'; import { gql, useQuery } from '../../../../admin-ui/apollo'; @@ -17,10 +18,7 @@ import { useRouter, Link } from '../../../../admin-ui/router'; type ListCardProps = { listKey: string; count: - | { - type: 'success'; - count: number; - } + | { type: 'success'; count: number } | { type: 'no-access' } | { type: 'error'; message: string } | { type: 'loading' }; @@ -160,7 +158,15 @@ export const HomePage = () => { ) : ( - + {(() => { if (visibleLists.state === 'error') { return ( diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx index a49288a34c7..8bc7a717d79 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import copyToClipboard from 'clipboard-copy'; import Link from 'next/link'; @@ -15,7 +16,6 @@ import { useState, } from 'react'; -import { ListMeta } from '@keystone-next/types'; import { Button } from '@keystone-ui/button'; import { Box, Center, Heading, Stack, Text, jsx, useTheme } from '@keystone-ui/core'; import { LoadingDots } from '@keystone-ui/loading'; @@ -26,6 +26,7 @@ import { Notice } from '@keystone-ui/notice'; import { useToasts } from '@keystone-ui/toast'; import { Tooltip } from '@keystone-ui/tooltip'; import { FieldLabel, TextInput } from '@keystone-ui/fields'; +import { ListMeta } from '../../../../types'; import { DataGetter, DeepNullable, @@ -35,7 +36,7 @@ import { useInvalidFields, Fields, useChangedFieldsAndDataForUpdate, -} from '@keystone-next/admin-ui-utils'; +} from '../../../../admin-ui/utils'; import { gql, useMutation, useQuery } from '../../../../admin-ui/apollo'; import { useList } from '../../../../admin-ui/context'; @@ -80,9 +81,7 @@ function ItemForm({ ${selectedFields} } }`, - { - errorPolicy: 'all', - } + { errorPolicy: 'all' } ); itemGetter = useMemo(() => { @@ -93,10 +92,7 @@ function ItemForm({ const [state, setValue] = useState(() => { const value = deserializeValue(list.fields, itemGetter); - return { - value, - item: itemGetter.data, - }; + return { value, item: itemGetter.data }; }); if ( !loading && @@ -104,10 +100,7 @@ function ItemForm({ (itemGetter.errors || []).every(x => x.path?.length !== 1) ) { const value = deserializeValue(list.fields, itemGetter); - setValue({ - value, - item: itemGetter.data, - }); + setValue({ value, item: itemGetter.data }); } const { changedFields, dataForUpdate } = useChangedFieldsAndDataForUpdate( @@ -125,12 +118,7 @@ function ItemForm({ setForceValidation(newForceValidation); if (newForceValidation) return; - update({ - variables: { - data: dataForUpdate, - id: itemGetter.get('id').data, - }, - }) + update({ variables: { data: dataForUpdate, id: itemGetter.get('id').data } }) // TODO -- Experimenting with less detail in the toasts, so the data lines are commented // out below. If we're happy with this, clean up the unused lines. .then(({ /* data, */ errors }) => { @@ -154,11 +142,7 @@ function ItemForm({ } }) .catch(err => { - toasts.addToast({ - title: 'Failed to update item', - tone: 'negative', - message: err.message, - }); + toasts.addToast({ title: 'Failed to update item', tone: 'negative', message: err.message }); }); }); const labelFieldValue = itemGetter.data?.[list.labelField]; @@ -178,10 +162,7 @@ function ItemForm({ invalidFields={invalidFields} onChange={useCallback( value => { - setValue(state => ({ - item: state.item, - value: value(state.value), - })); + setValue(state => ({ item: state.item, value: value(state.value) })); }, [setValue] )} @@ -191,10 +172,7 @@ function ItemForm({ onSave={onSave} hasChangedFields={!!changedFields.size} onReset={useEventCallback(() => { - setValue({ - item: itemGetter.data, - value: deserializeValue(list.fields, itemGetter), - }); + setValue({ item: itemGetter.data, value: deserializeValue(list.fields, itemGetter) }); })} loading={loading} deleteButton={useMemo( @@ -255,7 +233,7 @@ function DeleteButton({ action: async () => { try { await deleteItem(); - } catch (err) { + } catch (err: any) { return toasts.addToast({ title: `Failed to delete ${list.singular} item: ${itemLabel}`, message: err.message, @@ -336,14 +314,7 @@ const ItemPage = ({ listKey }: ItemPageProps) => { item: ItemData; keystone: { adminMeta: { - list: { - fields: { - path: string; - itemView: { - fieldMode: 'edit' | 'read' | 'hidden'; - }; - }[]; - }; + list: { fields: { path: string; itemView: { fieldMode: 'edit' | 'read' | 'hidden' } }[] }; }; }; }> diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx index 11e517ec534..b4a4bd82762 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx @@ -1,11 +1,12 @@ +/** @jsxRuntime classic */ /** @jsx jsx */ -import { ListMeta } from '@keystone-next/types'; import { Button } from '@keystone-ui/button'; import { Box, jsx } from '@keystone-ui/core'; import { ChevronDownIcon } from '@keystone-ui/icons/icons/ChevronDownIcon'; import { Options, OptionPrimitive, CheckMark } from '@keystone-ui/options'; import { Popover } from '@keystone-ui/popover'; import { useRouter } from 'next/router'; +import { ListMeta } from '../../../../types'; import { useSelectedFields } from './useSelectedFields'; function isArrayEqual(arrA: string[], arrB: string[]) { @@ -46,16 +47,9 @@ export function FieldSelection({ const setNewSelectedFields = (selectedFields: string[]) => { if (isArrayEqual(selectedFields, list.initialColumns)) { const { fields: _ignore, ...otherQueryFields } = router.query; - router.push({ - query: otherQueryFields, - }); + router.push({ query: otherQueryFields }); } else { - router.push({ - query: { - ...router.query, - fields: selectedFields.join(','), - }, - }); + router.push({ query: { ...router.query, fields: selectedFields.join(',') } }); } }; const fields: { value: string; label: string; isDisabled: boolean }[] = []; @@ -71,8 +65,7 @@ export function FieldSelection({ return ( { return ( void; li > = {}; Object.keys(list.fields).forEach(fieldPath => { const field = list.fields[fieldPath]; - if (field.controller.filter) { + if (field.isFilterable && field.controller.filter) { // TODO: make all the things readonly so this works fieldsWithFilters[fieldPath] = field as any; } @@ -156,9 +142,7 @@ function FilterAddPopoverContent({ onClose, listKey }: { onClose: () => void; li
    { const fieldPath: string = (newVal as any).value; if (fieldPath === noFieldOption.value) { const { sortBy, ...restOfQuery } = router.query; - router.push({ - query: restOfQuery, - }); + router.push({ query: restOfQuery }); } else { router.push({ query: { @@ -114,10 +98,7 @@ function SortSelectionPopoverContent({ onClose, list }: { onClose: () => void; l }} options={Object.keys(list.fields) .filter(fieldPath => list.fields[fieldPath].isOrderable) - .map(fieldPath => ({ - label: list.fields[fieldPath].label, - value: fieldPath, - })) + .map(fieldPath => ({ label: list.fields[fieldPath].label, value: fieldPath })) .concat(noFieldOption)} /> diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx index a3f1e6203ca..549a629679e 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx @@ -1,8 +1,8 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { Fragment, HTMLAttributes, ReactNode, useEffect, useMemo, useState } from 'react'; -import { ListMeta } from '@keystone-next/types'; import { Button } from '@keystone-ui/button'; import { Box, Center, Heading, jsx, Stack, useTheme } from '@keystone-ui/core'; import { CheckboxControl } from '@keystone-ui/fields'; @@ -11,12 +11,13 @@ import { LoadingDots } from '@keystone-ui/loading'; import { AlertDialog, DrawerController } from '@keystone-ui/modals'; import { useToasts } from '@keystone-ui/toast'; +import { ListMeta } from '../../../../types'; import { getRootGraphQLFieldsFromFieldController, DataGetter, DeepNullable, makeDataGetter, -} from '@keystone-next/admin-ui-utils'; +} from '../../../../admin-ui/utils'; import { gql, TypedDocumentNode, useMutation, useQuery } from '../../../../admin-ui/apollo'; import { CellLink } from '../../../../admin-ui/components'; import { CreateItemDrawer } from '../../../../admin-ui/components/CreateItemDrawer'; @@ -32,9 +33,7 @@ import { useFilters } from './useFilters'; import { useSelectedFields } from './useSelectedFields'; import { useSort } from './useSort'; -type ListPageProps = { - listKey: string; -}; +type ListPageProps = { listKey: string }; let listMetaGraphqlQuery: TypedDocumentNode< { @@ -43,13 +42,7 @@ let listMetaGraphqlQuery: TypedDocumentNode< list: { hideCreate: boolean; hideDelete: boolean; - - fields: { - path: string; - listView: { - fieldMode: 'read' | 'hidden'; - }; - }[]; + fields: { path: string; listView: { fieldMode: 'read' | 'hidden' } }[]; } | null; }; }; @@ -82,9 +75,7 @@ function useQueryParamsFromLocalStorage(listKey: string) { const resetToDefaults = () => { localStorage.removeItem(localStorageKey); - router.replace({ - pathname: router.pathname, - }); + router.replace({ pathname: router.pathname }); }; // GET QUERY FROM CACHE IF CONDITIONS ARE RIGHT @@ -102,12 +93,7 @@ function useQueryParamsFromLocalStorage(listKey: string) { parsed = JSON.parse(queryParamsFromLocalStorage!); } catch (err) {} if (parsed) { - router.replace({ - query: { - ...router.query, - ...parsed, - }, - }); + router.replace({ query: { ...router.query, ...parsed } }); } } }, @@ -207,19 +193,13 @@ const ListPage = ({ listKey }: ListPageProps) => { let [dataState, setDataState] = useState({ data: newData, error: newError }); if (newData && dataState.data !== newData) { - setDataState({ - data: newData, - error: newError, - }); + setDataState({ data: newData, error: newError }); } const { data, error } = dataState; const dataGetter = makeDataGetter< - DeepNullable<{ - count: number; - items: { id: string; [key: string]: any }[]; - }> + DeepNullable<{ count: number; items: { id: string; [key: string]: any }[] }> >(data, error?.graphQLErrors); const [selectedItemsState, setSelectedItems] = useState(() => ({ @@ -236,10 +216,7 @@ const ListPage = ({ listKey }: ListPageProps) => { newSelectedItems.add(item.id); } }); - setSelectedItems({ - itemsFromServer: data.items, - selectedItems: newSelectedItems, - }); + setSelectedItems({ itemsFromServer: data.items, selectedItems: newSelectedItems }); } const theme = useTheme(); @@ -444,9 +421,7 @@ function DeleteManyButton({ `, [list] ), - { - errorPolicy: 'all', - } + { errorPolicy: 'all' } ); const [isOpen, setIsOpen] = useState(false); const toasts = useToasts(); @@ -494,8 +469,8 @@ function DeleteManyButton({ acc.successfulItems++; acc.successMessage = acc.successMessage === '' - ? (acc.successMessage += curr.label) - : (acc.successMessage += `, ${curr.label}`); + ? (acc.successMessage += curr[list.labelField]) + : (acc.successMessage += `, ${curr[list.labelField]}`); } else { acc.unsuccessfulItems++; } @@ -671,7 +646,6 @@ function ListTable({ minHeight: 38, alignItems: 'center', justifyContent: 'start', - position: 'relative', }} > ) => { padding: spacing.small, textAlign: 'left', position: 'sticky', - zIndex: 1, top: 0, }} {...props} diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useFilters.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useFilters.tsx index e3655a35dd3..454f40354c8 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useFilters.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useFilters.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { JSONValue, ListMeta } from '@keystone-next/types'; +import { JSONValue, ListMeta } from '../../../../types'; import { useRouter } from '../../../../admin-ui/router'; export type Filter = { field: string; type: string; value: JSONValue }; @@ -11,10 +11,7 @@ export function useFilters(list: ListMeta) { Object.entries(list.fields).forEach(([fieldPath, field]) => { if (field.controller.filter) { Object.keys(field.controller.filter.types).forEach(type => { - possibleFilters[`!${fieldPath}_${type}`] = { - type, - field: fieldPath, - }; + possibleFilters[`!${fieldPath}_${type}`] = { type, field: fieldPath }; }); } }); @@ -31,10 +28,7 @@ export function useFilters(list: ListMeta) { value = JSON.parse(val); } catch (err) {} if (val !== undefined) { - filters.push({ - ...filter, - value, - }); + filters.push({ ...filter, value }); } } }); diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSelectedFields.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSelectedFields.tsx index 8786bdb1a3b..28b3567719f 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSelectedFields.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSelectedFields.tsx @@ -1,5 +1,5 @@ -import { ListMeta } from '@keystone-next/types'; import { useMemo } from 'react'; +import { ListMeta } from '../../../../types'; import { useRouter } from '../../../../admin-ui/router'; export function useSelectedFields( diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSort.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSort.tsx index 6e4b29bc748..7a7fb40e787 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSort.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/useSort.tsx @@ -1,5 +1,5 @@ -import { ListMeta } from '@keystone-next/types'; import { useMemo } from 'react'; +import { ListMeta } from '../../../../types'; import { useRouter } from '../../../../admin-ui/router'; export function useSort(list: ListMeta) { @@ -15,9 +15,6 @@ export function useSort(list: ListMeta) { direction = 'DESC'; } if (!list.fields[sortByField].isOrderable) return null; - return { - field: sortByField, - direction, - }; + return { field: sortByField, direction }; }, [sortByFromUrl, list]); } diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.tsx index 6b072dc1d63..b7f9fed0743 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage/index.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, Stack } from '@keystone-ui/core'; import { AlertTriangleIcon } from '@keystone-ui/icons/icons/AlertTriangleIcon'; diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts index 78ec432b4c4..1cf2125c87f 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/next-graphql.ts @@ -1,4 +1,4 @@ -import { KeystoneConfig } from '@keystone-next/types'; +import { KeystoneConfig } from '../types'; import { initConfig } from '../lib/config/initConfig'; import { createSystem } from '../lib/createSystem'; import { createApolloServerMicro } from '../lib/server/createApolloServer'; @@ -19,5 +19,5 @@ export function nextGraphQLAPIRoute(keystoneConfig: KeystoneConfig, prismaClient connectionPromise: keystone.connect(), }); - return apolloServer.createHandler({ path: '/api/graphql' }); + return apolloServer.createHandler({ path: keystoneConfig.graphql?.path || '/api/graphql' }); } diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts index 0ff1335df88..4d8357a2dc4 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts @@ -1,4 +1,4 @@ -import { KeystoneConfig } from '@keystone-next/types'; +import { KeystoneConfig } from '../types'; import { createSystem } from '../lib/createSystem'; import { initConfig } from '../lib/config/initConfig'; diff --git a/packages/keystone/src/admin-ui/admin-meta-graphql.ts b/packages/keystone/src/admin-ui/admin-meta-graphql.ts index 9deaeb37531..3f687820a08 100644 --- a/packages/keystone/src/admin-ui/admin-meta-graphql.ts +++ b/packages/keystone/src/admin-ui/admin-meta-graphql.ts @@ -1,4 +1,4 @@ -import { JSONValue } from '@keystone-next/types'; +import { JSONValue } from '../types'; import { gql } from './apollo'; export const staticAdminMetaQuery = gql` @@ -32,6 +32,7 @@ export const staticAdminMetaQuery = gql` path label isOrderable + isFilterable fieldMeta viewsIndex customViewsIndex @@ -88,6 +89,7 @@ export type StaticAdminMetaQuery = { __typename?: 'Query' } & { | 'path' | 'label' | 'isOrderable' + | 'isFilterable' | 'fieldMeta' | 'viewsIndex' | 'customViewsIndex' @@ -158,6 +160,7 @@ type KeystoneAdminUIFieldMeta = { path: Scalars['String']; label: Scalars['String']; isOrderable: Scalars['Boolean']; + isFilterable: Scalars['Boolean']; fieldMeta: Maybe; viewsIndex: Scalars['Int']; customViewsIndex: Maybe; diff --git a/packages/keystone/src/admin-ui/components/CellContainer.tsx b/packages/keystone/src/admin-ui/components/CellContainer.tsx index fcd9dc562ca..d4e7146b5c2 100644 --- a/packages/keystone/src/admin-ui/components/CellContainer.tsx +++ b/packages/keystone/src/admin-ui/components/CellContainer.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { ReactNode } from 'react'; import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/packages/keystone/src/admin-ui/components/CellLink.tsx b/packages/keystone/src/admin-ui/components/CellLink.tsx index 37c7151c5bd..f72af02171d 100644 --- a/packages/keystone/src/admin-ui/components/CellLink.tsx +++ b/packages/keystone/src/admin-ui/components/CellLink.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, useTheme } from '@keystone-ui/core'; diff --git a/packages/keystone/src/admin-ui/components/Container.tsx b/packages/keystone/src/admin-ui/components/Container.tsx index ac8d1f78bb6..512fd5f2b8f 100644 --- a/packages/keystone/src/admin-ui/components/Container.tsx +++ b/packages/keystone/src/admin-ui/components/Container.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { ComponentPropsWithoutRef } from 'react'; import { jsx } from '@keystone-ui/core'; diff --git a/packages/keystone/src/admin-ui/components/CreateItemDrawer.tsx b/packages/keystone/src/admin-ui/components/CreateItemDrawer.tsx index 7cf0fd219ee..5ef453becc8 100644 --- a/packages/keystone/src/admin-ui/components/CreateItemDrawer.tsx +++ b/packages/keystone/src/admin-ui/components/CreateItemDrawer.tsx @@ -1,8 +1,9 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ -import { useMemo, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import isDeepEqual from 'fast-deep-equal'; -import { jsx, Stack } from '@keystone-ui/core'; +import { jsx, Box } from '@keystone-ui/core'; import { Drawer } from '@keystone-ui/modals'; import { useToasts } from '@keystone-ui/toast'; import { LoadingDots } from '@keystone-ui/loading'; @@ -10,8 +11,11 @@ import { LoadingDots } from '@keystone-ui/loading'; import { gql, useMutation } from '../apollo'; import { useKeystone, useList } from '../context'; +import { Fields } from '../utils/Fields'; import { GraphQLErrorNotice } from './GraphQLErrorNotice'; +type ValueWithoutServerSideErrors = { [key: string]: { kind: 'value'; value: any } }; + export function CreateItemDrawer({ listKey, onClose, @@ -35,10 +39,10 @@ export function CreateItemDrawer({ }` ); - const [valuesByFieldPath, setValuesByFieldPath] = useState(() => { - const value: Record = {}; + const [value, setValue] = useState(() => { + const value: ValueWithoutServerSideErrors = {}; Object.keys(list.fields).forEach(fieldPath => { - value[fieldPath] = list.fields[fieldPath].controller.defaultValue; + value[fieldPath] = { kind: 'value', value: list.fields[fieldPath].controller.defaultValue }; }); return value; }); @@ -46,8 +50,8 @@ export function CreateItemDrawer({ const invalidFields = useMemo(() => { const invalidFields = new Set(); - Object.keys(valuesByFieldPath).forEach(fieldPath => { - const val = valuesByFieldPath[fieldPath]; + Object.keys(value).forEach(fieldPath => { + const val = value[fieldPath].value; const validateFn = list.fields[fieldPath].controller.validate; if (validateFn) { @@ -58,35 +62,10 @@ export function CreateItemDrawer({ } }); return invalidFields; - }, [list, valuesByFieldPath]); + }, [list, value]); const [forceValidation, setForceValidation] = useState(false); - const fields = Object.keys(list.fields) - .filter(fieldPath => - createViewFieldModes.state === 'loaded' - ? createViewFieldModes.lists[listKey][fieldPath] !== 'hidden' - : false - ) - .map((fieldPath, index) => { - const field = list.fields[fieldPath]; - return ( - { - setValuesByFieldPath({ - ...valuesByFieldPath, - [fieldPath]: fieldValue, - }); - }} - autoFocus={index === 0} - /> - ); - }); - return ( = {}; Object.keys(list.fields).forEach(fieldPath => { const { controller } = list.fields[fieldPath]; - const serialized = controller.serialize(valuesByFieldPath[fieldPath]); + const serialized = controller.serialize(value[fieldPath].value); if (!isDeepEqual(serialized, controller.serialize(controller.defaultValue))) { Object.assign(data, serialized); } @@ -146,10 +125,20 @@ export function CreateItemDrawer({ {error && ( )} - - {fields} - {fields.length === 0 && 'There are no fields that you can read or edit'} - + + { + setValue(oldValues => getNewValue(oldValues) as ValueWithoutServerSideErrors); + }, [])} + /> + ); } diff --git a/packages/keystone/src/admin-ui/components/Errors.tsx b/packages/keystone/src/admin-ui/components/Errors.tsx index 5ca195e422e..bc963a7f932 100644 --- a/packages/keystone/src/admin-ui/components/Errors.tsx +++ b/packages/keystone/src/admin-ui/components/Errors.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { Component, ReactNode } from 'react'; import { Button } from '@keystone-ui/button'; diff --git a/packages/keystone/src/admin-ui/components/Logo.tsx b/packages/keystone/src/admin-ui/components/Logo.tsx index 7da11cf023b..c206f8f0413 100644 --- a/packages/keystone/src/admin-ui/components/Logo.tsx +++ b/packages/keystone/src/admin-ui/components/Logo.tsx @@ -1,4 +1,5 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { jsx, useTheme, H3 } from '@keystone-ui/core'; import Link from 'next/link'; diff --git a/packages/keystone/src/admin-ui/components/Navigation.tsx b/packages/keystone/src/admin-ui/components/Navigation.tsx index 781855831ad..aac48c67c08 100644 --- a/packages/keystone/src/admin-ui/components/Navigation.tsx +++ b/packages/keystone/src/admin-ui/components/Navigation.tsx @@ -1,13 +1,14 @@ -/* @jsx jsx */ +/** @jsxRuntime classic */ +/** @jsx jsx */ import { AllHTMLAttributes, ReactNode, Fragment } from 'react'; import { useRouter } from 'next/router'; -import { NavigationProps, ListMeta } from '@keystone-next/types'; import { Stack, jsx, useTheme, Text } from '@keystone-ui/core'; import { Button } from '@keystone-ui/button'; import { Popover } from '@keystone-ui/popover'; import { MoreHorizontalIcon } from '@keystone-ui/icons/icons/MoreHorizontalIcon'; import { ChevronRightIcon } from '@keystone-ui/icons/icons/ChevronRightIcon'; +import { NavigationProps, ListMeta, AuthenticatedItem } from '../../types'; import { useKeystone } from '../context'; import { Link } from '../router'; @@ -59,7 +60,8 @@ export const NavItem = ({ href, children, isSelected: _isSelected }: NavItemProp ); }; -const AuthenticatedItem = ({ item }: { item: { id: string; label: string } }) => { +const AuthenticatedItemDialog = ({ item }: { item: AuthenticatedItem | undefined }) => { + const { apiPath } = useKeystone(); const { spacing, typography } = useTheme(); return (
    marginBottom: 0, }} > -
    - Signed in as {item.label} -
    + {item && item.state === 'authenticated' ? ( +
    + Signed in as {item.label} +
    + ) : ( +
    Graqhql Playground and Docs
    + )} + ( @@ -89,8 +96,7 @@ const AuthenticatedItem = ({ item }: { item: { id: string; label: string } }) => )} > - {/* FIXME: Use config.graphql.path */} - + API Explorer @@ -99,7 +105,7 @@ const AuthenticatedItem = ({ item }: { item: { id: string; label: string } }) => Keystone Documentation - + {item && item.state === 'authenticated' && }
    @@ -137,11 +143,10 @@ export const NavigationContainer = ({ authenticatedItem, children }: NavigationC display: 'flex', flexDirection: 'column', justifyContent: 'center', + position: 'relative', }} > - {authenticatedItem?.state === 'authenticated' && ( - - )} +