resource query (resource migration 1/3)#71
Conversation
✅ Deploy Preview for project-idea-board ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| resources: { | ||
| resolve: async (source, _args, context) => { | ||
| const names = resolveToArray(source.resources); | ||
| const results = await Promise.all( | ||
| names.map((name) => | ||
| context.nodeModel.findOne(resourceQuery(name)), | ||
| ), | ||
| ); | ||
| results.forEach((result, i) => { | ||
| if (!result) { | ||
| const msg = `Resource "${names[i]}" not found for idea "${source.title}". Check for typos and ensure the resource file exists with the correct templateKey.`; | ||
| reporter.error(msg, new Error(msg)); | ||
| } | ||
| }); | ||
| return results.filter(Boolean); | ||
| }, | ||
| }, |
There was a problem hiding this comment.
A different way to handle the resolution, using context.nodeModel.findOne, where before we would use a @link directive in the schema. Both are valid ways of doing things. I think I prefer this way because we get a bit more color, as in the example of doing error handling with the reporter.
https://www.gatsbyjs.com/docs/reference/graphql-data-layer/node-model/#findOne
Do we really need error handling here? We have some now.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…/idea-board into feature/resource-query
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…/idea-board into feature/resource-query
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
gatsby/schema/base.gql
Outdated
| materialsAndMethods: MaterialsAndMethods! | ||
| authors: [String!]! | ||
| nextSteps: [String!] | ||
| authors: [String!] |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| names.map((name) => | ||
| context.nodeModel.findOne(resourceQuery(name)), | ||
| ), |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
…eature/resource-query
| import * as React from "react"; | ||
| import { Helmet } from "react-helmet-async"; | ||
|
|
||
| import { Link, PageProps, graphql } from "gatsby"; | ||
|
|
||
| const ResourcesPage: React.FC<PageProps<Queries.ResourcesIndexQueryQuery>> = ({ | ||
| data, | ||
| }) => { | ||
| const { allResource, site } = data; | ||
|
|
||
| if (!allResource || !site) { | ||
| return <p>Data not found.</p>; | ||
| } | ||
|
|
||
| const { nodes } = allResource; | ||
| const title = site.siteMetadata?.title || "Title"; | ||
| return ( | ||
| <section> | ||
| <Helmet title={`Resources | ${title}`} /> | ||
| <div> | ||
| <h1>Resources</h1> | ||
| <ul> | ||
| {nodes.map((node) => ( | ||
| <li key={node.slug}> | ||
| <Link to={node.slug}>{node.name}</Link> | ||
| {node.description && <p>{node.description}</p>} | ||
| {node.type && <p>{node.type}</p>} | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| </div> | ||
| </section> | ||
| ); | ||
| }; | ||
|
|
||
| export default ResourcesPage; | ||
|
|
||
| export const resourcePageQuery = graphql` | ||
| query ResourcesIndexQuery { | ||
| site { | ||
| siteMetadata { | ||
| title | ||
| } | ||
| } | ||
| allResource { | ||
| nodes { | ||
| slug | ||
| ...ResourceFields | ||
| } | ||
| } |
There was a problem hiding this comment.
Mostly a proof of concept, just showing in all the relevant places that the new data and approach is working.
| (rapid local changes in junction length and intensity) increases ~30–60 | ||
| minutes before migration onset in a subset of fields of view. Here is a link for no reason: [link](https://allencell.org/). | ||
| minutes before migration onset in a subset of fields of view. Here is a link | ||
| for no reason: [link](https://allencell.org/). |
frasercl
left a comment
There was a problem hiding this comment.
I will have to make a point to learn a bit more about Gatsby! I left a couple basic clarifying questions about the style and architecture, at least one of which is bound to be dumb, but this is looking good as far as I can tell.
| const { | ||
| DATASET_PATH, | ||
| RESOURCES_GATSBY_NODE_KEY, | ||
| MARKDOWN_REMARK_GATSBY_NODE_KEY, | ||
| TEMPLATE_KEY_TO_TYPE, | ||
| } = require("./gatsby/constants"); |
There was a problem hiding this comment.
Another optional clarifying question: any rhyme or reason to what gets CommonJS-style vs ESM-style imports? I guess these and the files in gatsby/ are either config or server-side...?
There was a problem hiding this comment.
Historical anachronism from gatsby's age and the template this repo was started from.
I think webpack handles src and gatsby-browser.js and Node directly handles the other gatsby configuration files. I think we would need to migrate everything at once and it's just been low on my list, but it is starting to get annoying. Maybe I should do that next. Gatsby supports ESM now, it didn't always.
https://www.gatsbyjs.com/docs/how-to/custom-configuration/es-modules/
| IdeaFrontmatter["preliminaryFindings"] | ||
| >["figures"][number]; | ||
|
|
||
| export type ResourceTemplateQuery = Queries.ResourcesByIdQuery; |
There was a problem hiding this comment.
Large block comment above is very helpful for understanding why this works despite the red squiggle TS throws up on Queries
There was a problem hiding this comment.
Yes... Curious if it smells bad to you to be defining types downstream of the generated types.
In cell-catalog we wrote types based on what we expected the queries to give back which gave rise to some interesting bugs. This way is a little annoying, but it keeps the data layer and the front end in tighter lock step.
|
|
||
| import { Link, PageProps, graphql } from "gatsby"; | ||
|
|
||
| const ResourcesPage: React.FC<PageProps<Queries.ResourcesIndexQueryQuery>> = ({ |
There was a problem hiding this comment.
Seeing some query types with Query at the end in the graphql declaration, resulting in this QueryQuery name in TS, and some without. Any reason for some to be one vs. the other?
There was a problem hiding this comment.
Mmm just style, I think before we were using the generated types we had a pattern of putting query at the end of the name, and now should probably be moving away from that since it produces the redundancy.
There was a problem hiding this comment.
Out of curiosity: any reason this file is a plain .js file?
There was a problem hiding this comment.
We initialized this repo from a template, we are migrating away from their style over time, but some things are in the old style which included a lot of plain JS.
I'm tackling patterns like this as I hit them, to avoid massive, unreviewable refactors.
…eature/resource-query
Problem
Advances #40
Line count inflated by formatting stuff. Next priority needs to be getting those pre commit checks up and running so we can iron that out.
Next PR in series is here: #72
Solution
We have created a single resource collection in the CMS. Now we need to consume these resources.
The primary goals of this PR are to successfully convert those resource markdown files into useful
gatsbynodes, build the pages associated with resources, and query the resource nodes wherever they are needed.gatsbyimprovements and upgrades come along for the ride.Resource Nodes
Up until now, all our nodes in our
gatsbydata layer were of typeMarkdownRemark. This has pros and cons. In this PR we create a typeResourcethat implementsNodeThis resource type is flat, relative to MarkdownRemark, in that it does not have
frontmatterorfieldsbut only top level properties.It is also flat relative the resource .md files in that it does not have a nested
ResourceDetailsfield, but only top level properties.It can be queried with
allResourceandresourcewhich is a nice option to have.These nodes are created explicitly in
onCreateNode. TheMarkdownRemarknodes are created, mysteriously, by a plugin.Resolvers
Resolvers can take direct advantage of these nodes, we should have done this before. See the
resourcesresolver for a nice pattern usingcontext.nodeModel.findOne(resourceQuery(name))This typing and way of handling the resolver replaces the@linkdirective in a way that is more pleasant.onCreateNode and createPages
We make resource nodes and resource pages in a way that is extendable to other forthcoming types. We map over
TEMPLATE_KEY_TO_TYPE. This wasn't strictly necessary for this PR but it's good practice and I know another use is right around the corner. When we want to make anAllenitenode or page, or aProgramnode or page, it will be set up.