Skip to content

Commit

Permalink
feat(gatsby-recipes): Spike out contentful provider and basic renderi…
Browse files Browse the repository at this point in the history
…ng (#24655)

* feat(gatsby-recipes): Spike out contentful provider and basic rendering

* Update packages/gatsby-recipes/src/gui.js
  • Loading branch information
johno authored May 30, 2020
1 parent 16880e0 commit 69ce2e9
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 31 deletions.
41 changes: 37 additions & 4 deletions packages/gatsby-recipes/src/gui.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ const ContentfulSpace = ({ _uuid, ...props }) => {
},
})

const { children, ...editableProps } = props

const setProp = key => e => {
const newState = {
...inputState,
Expand All @@ -193,7 +195,7 @@ const ContentfulSpace = ({ _uuid, ...props }) => {

return (
<form key={_uuid}>
{Object.entries(props).map(([key, value]) => (
{Object.entries(editableProps).map(([key, value]) => (
<label key={key}>
{key} <br />
<input
Expand Down Expand Up @@ -263,6 +265,8 @@ const components = {
RecipeIntroduction: props => <div>{props.children}</div>,
RecipeStep: props => <div>{props.children}</div>,
ContentfulSpace,
ContentfulEnvironment: () => null,
ContentfulType: () => null,
}

const log = (label, textOrObj) => {
Expand Down Expand Up @@ -434,6 +438,11 @@ const RecipeGui = ({
}}
/>
)}
{resourcePlan.resourceChildren
? resourcePlan.resourceChildren.map(resource => (
<ResourcePlan key={resource._uuid} resourcePlan={resource} />
))
: null}
</div>
)

Expand All @@ -444,13 +453,10 @@ const RecipeGui = ({
date: new Date(),
})

console.log(state.context.plan, i)
const stepResources = state.context?.plan?.filter(
p => parseInt(p._stepMetadata.step, 10) === i + 1
)

console.log({ stepResources })

const [complete, setComplete] = useState(false)
if (output.title !== `` && output.body !== ``) {
setTimeout(() => {
Expand Down Expand Up @@ -715,6 +721,30 @@ const RecipeGui = ({
return `Install Recipe`
}

const ResourceChildren = ({ resourceChildren }) => {
if (!resourceChildren || !resourceChildren.length) {
return null
}

return (
<Styled.ul sx={{ pl: 3, marginTop: 0, mb: 5 }}>
{resourceChildren.map(resource => (
<Styled.li
sx={{
listStyleType: `none`,
}}
key={resource._uuid}
>
<ResourceMessage resource={resource} />
<ResourceChildren
resourceChildren={resource.resourceChildren}
/>
</Styled.li>
))}
</Styled.ul>
)
}

return (
<InputProvider value={state.context.inputs || {}}>
<Wrapper>
Expand Down Expand Up @@ -767,6 +797,9 @@ const RecipeGui = ({
key={`${resourceName}-plan-${i}`}
>
<ResourceMessage resource={p} />
<ResourceChildren
resourceChildren={p.resourceChildren}
/>
</Styled.li>
))}
</Styled.ul>
Expand Down
66 changes: 66 additions & 0 deletions packages/gatsby-recipes/src/providers/contentful/environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import Joi from "@hapi/joi"

import client from "./client"
import space from "./client"
import resourceSchema from "../resource-schema"

const create = async (context, { name }) => {
const spaceId = context.ContentfulSpace.id
const space = await client.getSpace(spaceId)
const environment = await space.createEnvironment({ name })

return {
name: environment.name,
id: environment.sys.id,
_message: message(environment),
}
}

const read = async (context, name) => {
console.log({ context, name })

return undefined
}

const destroy = async (_context, id) => {}

const all = async () => {}

const schema = {
name: Joi.string(),
...resourceSchema,
}

const validate = resource =>
Joi.validate(resource, schema, { abortEarly: false })

const plan = async (context, { id, name }) => {
console.log({ context, name, id })
const currentResource = await read(context, id || name)

if (!currentResource) {
return {
currentState: ``,
describe: `Create Contentful environment ${name}`,
diffExists: true,
skipDiff: true,
}
} else {
return {
currentState: currentResource,
describe: `Contentful environment ${name} already exists`,
diff: ``,
}
}
}

const message = resource => `Created Contentful environment "${resource.name}"`

module.exports.schema = schema
module.exports.validate = validate
module.exports.plan = plan
module.exports.create = create
module.exports.read = read
module.exports.update = create
module.exports.destroy = destroy
module.exports.all = all
69 changes: 69 additions & 0 deletions packages/gatsby-recipes/src/providers/contentful/type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import Joi from "@hapi/joi"

import client from "./client"
import space from "./client"
import resourceSchema from "../resource-schema"
import getGraphqlFields from "../utils/get-graphql-fields"

const GRAPHQL_FIELD_OPTIONS = {
metadata: [`type`, `name`],
}

const create = async (context, { schema }) => {
const spaceId = context.ContentfulSpace.id
const space = await client.getSpace(spaceId)

const fields = getGraphqlFields(schema, GRAPHQL_FIELD_OPTIONS)[0]
const contentType = await space.createContentTypeWithId(fields.name, fields)
await contentType.publish()

return {
name: contentType.name,
id: contentType.sys.id,
_message: message(contentType),
}
}

const read = async (context, name) => {}

const destroy = async (_context, id) => {}

const all = async () => {}

const schema = {
schema: Joi.string(),
...resourceSchema,
}

const validate = resource =>
Joi.validate(resource, schema, { abortEarly: false })

const plan = async (context, { id, schema }) => {
const currentResource = await read(context, id)

if (!currentResource) {
return {
currentState: ``,
describe: `Create Contentful type`,
diffExists: true,
skipDiff: true,
}
} else {
return {
currentState: currentResource,
describe: `Contentful type ${currentResource.name} already exists`,
diff: ``,
}
}
}

const message = resource => `Created Contentful type "${resource.name}"`

module.exports.schema = schema
module.exports.validate = validate
module.exports.plan = plan
module.exports.create = create
module.exports.read = read
module.exports.update = create
module.exports.destroy = destroy
module.exports.all = all
16 changes: 10 additions & 6 deletions packages/gatsby-recipes/src/providers/utils/get-graphql-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ const {
SchemaDirectiveVisitor,
} = require(`graphql-tools`)

const gqlFieldsToObject = fields =>
const gqlFieldsToArray = fields =>
Object.entries(fields).reduce((acc, [key, value]) => {
acc[key] = {
const metadata = value.metadata || {}
const field = {
id: key,
type: value.type,
metadata: value.metadata,
name: key,
...metadata,
}
return acc
}, {})

return [...acc, field]
}, [])

class MetadataDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
Expand Down Expand Up @@ -55,7 +59,7 @@ module.exports = (typeDefs, { metadata } = {}) => {
.map(([key, value]) => {
return {
name: key,
fields: gqlFieldsToObject(value._fields),
fields: gqlFieldsToArray(value._fields),
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ test(`get-graphql-fields returns an array of fields`, () => {
expect(result).toMatchInlineSnapshot(`
Array [
Object {
"fields": Object {
"body": Object {
"metadata": Object {
"title": "Content",
"type": "Text",
},
"fields": Array [
Object {
"id": "title",
"name": "title",
"type": "String",
},
"title": Object {
"metadata": undefined,
"type": "String",
Object {
"id": "body",
"name": "body",
"title": "Content",
"type": "Text",
},
},
],
"name": "BlogPost",
},
]
Expand Down
29 changes: 21 additions & 8 deletions packages/gatsby-recipes/src/renderer/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import resources from "../resources"
import RecipesReconciler from "./reconciler"
import ErrorBoundary from "./error-boundary"
import transformToPlan from "./transform-to-plan-structure"
import { ResourceProvider } from "./resource-provider"
import { ResourceProvider, useResourceContext } from "./resource-provider"
import { useRecipeStep } from "./step-component"
import { InputProvider, useInputByUuid } from "./input-provider"

Expand Down Expand Up @@ -53,12 +53,13 @@ const ResourceComponent = ({
const { mode } = useMode()
const step = useRecipeStep()
const inputProps = useInputByUuid(_uuid)
const resourceContext = useResourceContext()
const userProps = getUserProps(props)
const allProps = { ...props, ...inputProps }

const resourceData = handleResource(
Resource,
{ root: process.cwd(), _uuid, mode },
{ ...resourceContext, root: process.cwd(), _uuid, mode },
allProps
)

Expand Down Expand Up @@ -96,6 +97,7 @@ const handleResource = (resourceName, context, props) => {
const { mode } = context

const key = JSON.stringify({ resourceName, ...props, mode })

const cachedResult = cache.get(key)

if (cachedResult) {
Expand All @@ -106,12 +108,23 @@ const handleResource = (resourceName, context, props) => {

let promise
try {
promise = resources[resourceName][fn](context, props)
.then(result => cache.set(key, result))
.catch(e => {
console.log(e)
throw e
})
promise = new Promise((resolve, reject) => {
// Multiple of the same promises can be queued due to re-rendering
// so this first checks for the cached result again before executing
// the request.
const cachedValue = cache.get(key)
if (cachedValue) {
resolve(cachedValue)
}

resources[resourceName][fn](context, props)
.then(result => cache.set(key, result))
.then(resolve)
.catch(e => {
console.log(e)
reject(e)
})
})
} catch (e) {
throw e
}
Expand Down
4 changes: 2 additions & 2 deletions packages/gatsby-recipes/src/renderer/resource-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useContext } from "react"

const ResourceContext = React.createContext({})

export const useResourceContext = resourceName => {
export const useResourceContext = () => {
const context = useContext(ResourceContext)
return context[resourceName]
return context
}

export const ResourceProvider = ({ data: providedData, children }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ const transform = (props = {}) => {
return [...acc, ...childResourcePlans]
}

const { _props, ...plan } = JSON.parse(curr.children[0].text)
const [rawResource, ...resourceChildren] = curr.children
const { _props, ...plan } = JSON.parse(rawResource.text)

const resourcePlan = {
resourceName: curr.type,
resourceDefinitions: _props,
...plan,
}

if (resourceChildren.length) {
resourcePlan.resourceChildren = transform({ children: resourceChildren })
}

return [...acc, resourcePlan]
}, [])

Expand Down
Loading

0 comments on commit 69ce2e9

Please sign in to comment.