From 1c5da45d7aee2b4af16d0d83fe514d3e13f0d0e9 Mon Sep 17 00:00:00 2001 From: Holly Cummins Date: Tue, 6 Dec 2022 10:42:34 +0000 Subject: [PATCH] Where available, use the GitHub organisation avatar as the image for an extension --- gatsby-config.js | 8 +++ package-lock.json | 10 +++ package.json | 1 + plugins/github-enricher/gatsby-node.js | 45 ++++++++++++++ plugins/github-enricher/gatsby-node.test.js | 68 +++++++++++++++++++++ plugins/github-enricher/package.json | 3 + src/components/extension-card.js | 41 ++++++++++--- src/components/extension-card.test.js | 8 +++ src/pages/index.js | 5 ++ 9 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 plugins/github-enricher/gatsby-node.js create mode 100644 plugins/github-enricher/gatsby-node.test.js create mode 100644 plugins/github-enricher/package.json diff --git a/gatsby-config.js b/gatsby-config.js index 966c99350e95..aaeccf18682d 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -22,6 +22,14 @@ module.exports = { path: `${__dirname}/src/images`, }, }, + `github-enricher`, + { + resolve: `gatsby-plugin-remote-images`, + options: { + nodeType: "extension", + imagePath: "fields.sourceControlInfo.logoUrl", + }, + }, { resolve: `gatsby-transformer-remark`, options: { diff --git a/package-lock.json b/package-lock.json index d607e962a9fa..1003e1d40029 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8490,6 +8490,16 @@ "lodash": "^4.17.21" } }, + "gatsby-plugin-remote-images": { + "version": "3.6.0-alpha", + "resolved": "https://registry.npmjs.org/gatsby-plugin-remote-images/-/gatsby-plugin-remote-images-3.6.0-alpha.tgz", + "integrity": "sha512-8keZtTiHaIfrknIinMX8diuct/mD/QqpFbj38/Sm8L2sGZv5NSGFwaEeDv+krTU8fEENLbVtXaYK8c4qJ8yViQ==", + "requires": { + "gatsby-source-filesystem": "^4.0.0", + "lodash": "^4.17.15", + "probe-image-size": "7.2.3" + } + }, "gatsby-plugin-sharp": { "version": "4.22.0", "resolved": "https://registry.npmjs.org/gatsby-plugin-sharp/-/gatsby-plugin-sharp-4.22.0.tgz", diff --git a/package.json b/package.json index f1104d13cc87..271e247c8dee 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "gatsby-plugin-fontawesome-css": "^1.2.0", "gatsby-plugin-image": "^2.22.0", "gatsby-plugin-manifest": "^4.22.0", + "gatsby-plugin-remote-images": "^3.6.0-alpha", "gatsby-plugin-sharp": "^4.22.0", "gatsby-plugin-styled-components": "^5.23.0", "gatsby-remark-copy-linked-files": "^5.22.0", diff --git a/plugins/github-enricher/gatsby-node.js b/plugins/github-enricher/gatsby-node.js new file mode 100644 index 000000000000..c61b7e8360d0 --- /dev/null +++ b/plugins/github-enricher/gatsby-node.js @@ -0,0 +1,45 @@ +const defaultOptions = { + nodeType: "extension", +} + +exports.onCreateNode = async ({ node, getNode, actions }, pluginOptions) => { + const { createNodeField } = actions + + const options = { + ...defaultOptions, + ...pluginOptions, + } + + if (node.internal.type !== options.nodeType) { + return + } + + const { metadata } = node + const scmUrl = metadata["scm-url"] + + if (scmUrl) { + // We should do this properly with the API, but for now make an educated guess about the image URL + // See https://stackoverflow.com/questions/22932422/get-github-avatar-from-email-or-name + // remove everything after the last backslash + const orgUrl = scmUrl.substr(0, scmUrl.lastIndexOf("/")) + const logoUrl = orgUrl + ".png" + const scmInfo = { url: scmUrl, logoUrl } + + createNodeField({ + node, + name: "sourceControlInfo", + value: scmInfo, + }) + } +} + +exports.createSchemaCustomization = ({ actions }) => { + const { createTypes } = actions + const typeDefs = ` + type SourceControlInfo implements Node { + url: String + logo: String + } + ` + createTypes(typeDefs) +} diff --git a/plugins/github-enricher/gatsby-node.test.js b/plugins/github-enricher/gatsby-node.test.js new file mode 100644 index 000000000000..f3ffaa611c7e --- /dev/null +++ b/plugins/github-enricher/gatsby-node.test.js @@ -0,0 +1,68 @@ +const { onCreateNode } = require("./gatsby-node") + +// This test relies on a mock in __mocks__. To validate things against +// the real implementation, rename __mocks__/node-geocoder.js to something else temporarily. + +const createNodeField = jest.fn(({ node, name, value }) => { + if (!node.fields) { + node.fields = {} + } + node.fields[name] = value +}) +const actions = { createNodeField } +const internal = { type: "extension" } + +describe("the preprocessor", () => { + describe("for an extension with no scm information", () => { + const metadata = {} + + const node = { + metadata, + internal, + } + + beforeAll(async () => { + await onCreateNode({ node, actions }) + }) + + afterAll(() => {}) + + it("changes nothing", async () => { + expect(node.metadata).toEqual({}) + expect(node.sourceControlInfo).toBeUndefined() + }) + }) + + describe("for an extension with a scm-url", () => { + const url = "http://gitsomething.com/someuser/somerepo" + const imageUrl = "http://gitsomething.com/someuser.png" + const metadata = { + "scm-url": url, + } + + const node = { + metadata, + internal, + } + + beforeAll(async () => { + await onCreateNode({ node, actions }) + }) + + afterAll(() => {}) + + it("creates an scm object", async () => { + expect(node.fields.sourceControlInfo).toBeTruthy() + }) + + it("copies across the url", async () => { + expect(node.fields.sourceControlInfo.url).toEqual(url) + }) + + it("fills in an image", async () => { + expect(node.fields.sourceControlInfo.logoUrl).toEqual(imageUrl) + }) + + xit("adds a node for the remote image", async () => {}) + }) +}) diff --git a/plugins/github-enricher/package.json b/plugins/github-enricher/package.json new file mode 100644 index 000000000000..31038842ef85 --- /dev/null +++ b/plugins/github-enricher/package.json @@ -0,0 +1,3 @@ +{ + "name": "github-enricher" +} diff --git a/src/components/extension-card.js b/src/components/extension-card.js index 15fdbbd4f986..c74e92b0ec2f 100644 --- a/src/components/extension-card.js +++ b/src/components/extension-card.js @@ -1,9 +1,9 @@ import * as React from "react" -import { StaticImage } from "gatsby-plugin-image" import Link from "gatsby-link" import styled from "styled-components" import prettyCategory from "./util/pretty-category" +import { GatsbyImage, StaticImage } from "gatsby-plugin-image" const Card = styled(props => )` font-size: 3.5em; @@ -24,8 +24,11 @@ const Card = styled(props => )` const Logo = styled.div` width: 80px; - height: 56px; + height: 80px; margin-bottom: 25px; + display: flex; + justify-content: center; + align-items: center; ` const ExtensionName = styled.div` @@ -65,18 +68,36 @@ const FinerDetails = styled.div` padding-bottom: 30px; ` +const logo = extension => { + if (extension.localImage?.childImageSharp?.gatsbyImageData) { + return ( + + + + ) + } else { + return ( + + + + ) + } +} + const ExtensionCard = ({ extension }) => { return ( - - - + {logo(extension)} {extension.name} diff --git a/src/components/extension-card.test.js b/src/components/extension-card.test.js index dab972b96acb..d9a860ee70b7 100644 --- a/src/components/extension-card.test.js +++ b/src/components/extension-card.test.js @@ -35,6 +35,14 @@ describe("extension card", () => { it("renders the version", () => { expect(screen.getByText("Version: " + version)).toBeTruthy() }) + + it("renders a placeholder image with appropriate source ", async () => { + const image = screen.getByAltText( + "A generic image as a placeholder for the extension logo" + ) + + expect(image.src).toContain("generic-extension-logo.png") + }) }) describe("an unlisted extension", () => { diff --git a/src/pages/index.js b/src/pages/index.js index 7f9e516e1448..ae26c3d8b34b 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -56,6 +56,11 @@ export const pageQuery = graphql` } } platforms + localImage { + childImageSharp { + gatsbyImageData(width: 80) + } + } } } }