From b01cf28dccc662084ca9cbac08b2c44d1fb5f49a Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 10:03:00 -0600 Subject: [PATCH 01/27] a release note about release notes --- .../2023-12-31-new-release-notes-structure.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 source/release-notes/2023-12-31-new-release-notes-structure.md diff --git a/source/release-notes/2023-12-31-new-release-notes-structure.md b/source/release-notes/2023-12-31-new-release-notes-structure.md new file mode 100644 index 0000000000..b85a37bdfd --- /dev/null +++ b/source/release-notes/2023-12-31-new-release-notes-structure.md @@ -0,0 +1,20 @@ +--- +title: New Release Notes Structure +publish_dated: "2023-12-31" +--- + +# New Release Notes Structure + +For nearly a decade, we have published a monthly "changelog" here within our Documentation site that summarizes significant changes to the platform. +Going forward in 2024 we are changing some of the details of how we publish and organize this information. + +Rather than treating the monthly retrospective as the base unit of information, we will instead publish a new "Release Note" for each significant change to the platform as needed, rather than waiting for the monthly summary. + +This switch will support more proactive communication and ensure that any noteworthy change is marked here in addition to the blog posts, emails, and other channels we use to communicate with our customers. + +Here you will find: +* A listing of all Release Notes at docs.pantheon.io/release-notes +* A listing of Release Notes by category like docs.pantheon.io/release-notes/infrastructure +# todo or should it be docs.pantheon.io/release-notes/all/2023/12 ? +* A month-by-month breakdown of all Release Notes like docs.pantheon.io/release-notes/all/2023-12 +* A month-by-month breakdown of Release Notes by catetory and month like docs.pantheon.io/release-notes/infrastructure/2023-12 From b9139943e2b2c0b61050c9e901c968384aea3176 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 10:03:21 -0600 Subject: [PATCH 02/27] a release note about release notes --- source/release-notes/2023-12-31-new-release-notes-structure.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/release-notes/2023-12-31-new-release-notes-structure.md b/source/release-notes/2023-12-31-new-release-notes-structure.md index b85a37bdfd..08db16388e 100644 --- a/source/release-notes/2023-12-31-new-release-notes-structure.md +++ b/source/release-notes/2023-12-31-new-release-notes-structure.md @@ -15,6 +15,5 @@ This switch will support more proactive communication and ensure that any notewo Here you will find: * A listing of all Release Notes at docs.pantheon.io/release-notes * A listing of Release Notes by category like docs.pantheon.io/release-notes/infrastructure -# todo or should it be docs.pantheon.io/release-notes/all/2023/12 ? -* A month-by-month breakdown of all Release Notes like docs.pantheon.io/release-notes/all/2023-12 +* A month-by-month breakdown of all Release Notes like docs.pantheon.io/release-notes/all/2023-12 (todo or should it be docs.pantheon.io/release-notes/all/2023/12) * A month-by-month breakdown of Release Notes by catetory and month like docs.pantheon.io/release-notes/infrastructure/2023-12 From 441a713097b043f6b8b5d220990933f507932711 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 12:40:54 -0600 Subject: [PATCH 03/27] adding another sample --- .../2023-11-02-terminus-composer-logs-plugin.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 source/release-notes/2023-11-02-terminus-composer-logs-plugin.md diff --git a/source/release-notes/2023-11-02-terminus-composer-logs-plugin.md b/source/release-notes/2023-11-02-terminus-composer-logs-plugin.md new file mode 100644 index 0000000000..1597751f59 --- /dev/null +++ b/source/release-notes/2023-11-02-terminus-composer-logs-plugin.md @@ -0,0 +1,8 @@ +--- +title: Terminus Composer Logs Plugin 1.0.0 Released +publish_dated: "2023-11-02" +--- + +# New Release Notes Structure + +Visibility into composer logs has been a top customer request. Now, if you need to debug a composer build failure due to an error, install the Terminus Composer Logs plugin on your machine to view more details. Upstream Update logs are also available. Installation instructions and command usage can be found here in the [plugin's GitHub repository](https://github.com/pantheon-systems/terminus-composer-logs-plugin). From aecdfff1b0ba7bd0efa73a9d17649fe302c48956 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 12:56:49 -0600 Subject: [PATCH 04/27] rename dir --- .../2023-11-02-terminus-composer-logs-plugin.md | 0 .../2023-12-31-new-release-notes-structure.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename source/{release-notes => releasenotes}/2023-11-02-terminus-composer-logs-plugin.md (100%) rename source/{release-notes => releasenotes}/2023-12-31-new-release-notes-structure.md (100%) diff --git a/source/release-notes/2023-11-02-terminus-composer-logs-plugin.md b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md similarity index 100% rename from source/release-notes/2023-11-02-terminus-composer-logs-plugin.md rename to source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md diff --git a/source/release-notes/2023-12-31-new-release-notes-structure.md b/source/releasenotes/2023-12-31-new-release-notes-structure.md similarity index 100% rename from source/release-notes/2023-12-31-new-release-notes-structure.md rename to source/releasenotes/2023-12-31-new-release-notes-structure.md From 9744350594239e61bfdff2d5056b9fc6d0e29121 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 13:05:57 -0600 Subject: [PATCH 05/27] trying to get release notes pages generating --- gatsby-node.js | 79 ++++++++++++ src/templates/releaseNote.js | 160 ++++++++++++++++++++++++ src/templates/releaseNotesListing.js | 180 +++++++++++++++++++++++++++ 3 files changed, 419 insertions(+) create mode 100644 src/templates/releaseNote.js create mode 100644 src/templates/releaseNotesListing.js diff --git a/gatsby-node.js b/gatsby-node.js index 288a567556..ef18c9857d 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -184,6 +184,40 @@ exports.createPages = ({ graphql, actions }) => { } } + allReleaseNotes: allMdx( + filter: { + fileAbsolutePath: { regex: "/releasenotes/"} + }, + sort: { fields: [fileAbsolutePath], order: DESC } + ) { + edges { + + previous { + fields { + slug + } + } + + node { + id + frontmatter { + title + } + fields { + slug + } + } + + next { + fields { + slug + } + } + + } + } + + allChangelogs: allMdx( filter: { fileAbsolutePath: { regex: "/changelogs/"} @@ -309,6 +343,23 @@ exports.createPages = ({ graphql, actions }) => { }) }) + + + // Create each release note page. + const releaseNotes = result.data.allReleaseNotes.edges; + releaseNotes.forEach(releaseNote => { + const template = calculateTemplate(releaseNote.node, "releaseNote"); + createPage({ + path: releaseNote.node.fields.slug, + component: path.resolve(`./src/templates/${template}.js`), + context: { + slug: releaseNote.node.fields.slug, + }, + }) + console.log('hello'); + }) + + // Create Terminus Command pages const terminusCommands = result.data.dataJson.commands terminusCommands.forEach(command => { @@ -345,6 +396,34 @@ exports.createPages = ({ graphql, actions }) => { }) }) + // Create changelog pagination. + const ReleaseNotesPerPage = 6 + const numberOfReleaseNotePages = Math.ceil(changelogs.length / ReleaseNotesPerPage) + Array.from({ length: numberOfReleaseNotePages }).forEach((_, i) => { + const currentPage = i + 1; + const next = currentPage === 1 ? null : (currentPage === 2 ? `/release-notes/` : `/release-notes/page/${currentPage - 1}`); + const previous = currentPage < numberOfReleaseNotePages ? `/changelog/page/${currentPage + 1}` : null; + createPage({ + path: i === 0 ? `/release-notes/` : `/release-notes/page/${i + 1}`, + component: path.resolve("./src/templates/release-notes.js"), + context: { + limit: ReleaseNotesPerPage, + skip: i * ReleaseNotesPerPage, + numberOfReleaseNotePages, + currentPage, + previous, + next + }, + }) + }) + + + + + + + + // Create contributor pages. const contributors = result.data.allContributorYaml.edges contributors.forEach(contributor => { diff --git a/src/templates/releaseNote.js b/src/templates/releaseNote.js new file mode 100644 index 0000000000..86394e0e92 --- /dev/null +++ b/src/templates/releaseNote.js @@ -0,0 +1,160 @@ +import React from "react" +import { graphql } from "gatsby" +import { MDXRenderer } from "gatsby-plugin-mdx" +import { MDXProvider } from "@mdx-js/react" + +import Layout from "../layout/layout" +import NavButtons from "../components/navButtons" +import Alert from "../components/alert" +import Accordion from "../components/accordion" +import ExternalLink from "../components/externalLink" +import Popover from "../components/popover" +import TabList from "../components/tabList" +import Tab from "../components/tab" +import TOC from "../components/toc" +import Card from "../components/card" +import CardGroup from "../components/cardGroup" +import SEO from "../layout/seo" +import Enablement from "../components/enablement" +import Color from "../components/color.js" +import Download from "../components/download" + + +import { + Container, + Icon, + Pager, + SidebarLayout, +} from "@pantheon-systems/pds-toolkit-react" + +const shortcodes = { + Alert, + Accordion, + ExternalLink, + Popover, + TabList, + Tab, + Card, + CardGroup, + Enablement, + Color, + Download, +} + +// Set container width for search and main content. +const containerWidth = "standard" + +class ChangelogTemplate extends React.Component { + componentDidMount() { + $("[data-toggle=popover]").popover({ + trigger: "click", + }) + + $("body").on("click", function (e) { + $('[data-toggle="popover"]').each(function () { + if ( + !$(this).is(e.target) && + $(this).has(e.target).length === 0 && + $(".popover").has(e.target).length === 0 + ) { + $(this).popover("hide") + } + }) + }) + + $("body").keyup(function (e) { + $('[data-toggle="popover"]').each(function () { + if (event.which === 27) { + $(this).popover("hide") + } + }) + }) + } + + render() { + const node = this.props.data.mdx + + return ( + + +
+ +
+ Pantheon Changelog +
+

{node.frontmatter.title}

+
+

+ Sign up for the Pantheon Changelog Newsletter to receive a + monthly email on what's new and improved across the platform. +

+ + Subscribe Now + + +
+
+ + +
+
+
+
+ + {node.body} + +
+
+
+
+ +
+ +
+
+
+ ) + } +} + +export default ChangelogTemplate + +export const pageQuery = graphql` + query ChangelogBySlug($slug: String!) { + mdx(fields: { slug: { eq: $slug } }) { + id + body + fields { + slug + } + frontmatter { + title + } + } + } +` diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js new file mode 100644 index 0000000000..18f5e7c433 --- /dev/null +++ b/src/templates/releaseNotesListing.js @@ -0,0 +1,180 @@ +import React from "react" +import { graphql, Link } from "gatsby" +import { MDXRenderer } from "gatsby-plugin-mdx" +import { MDXProvider } from "@mdx-js/react" + +import Layout from "../layout/layout" +import NavButtons from "../components/navButtons" +import Callout from "../components/callout" +import Alert from "../components/alert" +import Accordion from "../components/accordion" +import ExternalLink from "../components/externalLink" +import Popover from "../components/popover" +import TabList from "../components/tabList" +import Tab from "../components/tab" +import TOC from "../components/toc" +import Card from "../components/card" +import CardGroup from "../components/cardGroup" +import SEO from "../layout/seo" +import Enablement from "../components/enablement" +import Color from "../components/color.js" +import Download from "../components/download" + + +import { + headline1, + headline2, + headline3, + headline4, +} from "../components/releaseHeadlines" + +import { + Container, + Icon, + Pager, + SidebarLayout, +} from "@pantheon-systems/pds-toolkit-react" + +const shortcodes = { + Callout, + Alert, + Accordion, + ExternalLink, + Popover, + TabList, + Tab, + Card, + CardGroup, + Enablement, + Color, + Download, + h1: headline2, + h2: headline3, + h3: headline4, +} + +// Set container width for search and main content. +const containerWidth = "standard" + +// Combined changelog template. +class ChangelogsTemplate extends React.Component { + componentDidMount() { + $("[data-toggle=popover]").popover({ + trigger: "click", + }) + + $("body").on("click", function (e) { + $('[data-toggle="popover"]').each(function () { + if ( + !$(this).is(e.target) && + $(this).has(e.target).length === 0 && + $(".popover").has(e.target).length === 0 + ) { + $(this).popover("hide") + } + }) + }) + + $("body").keyup(function (e) { + $('[data-toggle="popover"]').each(function () { + if (event.which === 27) { + $(this).popover("hide") + } + }) + }) + } + + render() { + const changelogs = this.props.data.allMdx.edges + return ( + + +
+ +

Pantheon Changelog

+
+

+ Sign up for the Pantheon Changelog Newsletter to receive a + monthly email on what's new and improved across the platform. +

+ + Subscribe Now + + +
+
+ +
+
+
+
+ {changelogs.map((changelog) => ( + + +

+ {changelog.node.frontmatter.title} +

+ + + {changelog.node.body} + +
+ ))} +
+
+
+
+ +
+ +
+
+
+ ) + } +} + +export default ChangelogsTemplate + +export const pageQuery = graphql` + query Changelogs($skip: Int!, $limit: Int!) { + allMdx( + filter: { + fileAbsolutePath: { regex: "/changelogs/" } + frontmatter: { draft: { ne: true } } + } + sort: { fields: [fileAbsolutePath], order: DESC } + skip: $skip + limit: $limit + ) { + edges { + node { + id + body + frontmatter { + title + } + fields { + slug + } + } + } + } + } +` From bb2f193f9604c43da8a8206bd7dff443db22495a Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 13:51:24 -0600 Subject: [PATCH 06/27] starting to get release notes loading --- gatsby-config.js | 13 +++ gatsby-node.js | 102 ++++++------------ ...023-11-02-terminus-composer-logs-plugin.md | 3 + src/templates/releaseNotesListing.js | 5 +- 4 files changed, 51 insertions(+), 72 deletions(-) diff --git a/gatsby-config.js b/gatsby-config.js index 8e6af57400..ee16d4e5ce 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -97,6 +97,19 @@ module.exports = { name: `changelogs`, }, }, + + { + resolve: `gatsby-source-filesystem`, + options: { + path: `${__dirname}/source/releasenotes`, + name: `releasenotes`, + }, + }, + + + + + { resolve: `gatsby-source-filesystem`, options: { diff --git a/gatsby-node.js b/gatsby-node.js index ef18c9857d..cb29cf7e21 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -31,6 +31,12 @@ const calculateSlug = (node, getNode) => { const split = fileName.split('-'); // split the file name where hyphenated... return `changelog/${split[0]}/${split[1]}` // and return a slug of changelog/YYYY/MM } + // This section creates the releasenotes slug based on the YYYY-MM-DD-slug.md template + if (getNode(node.parent).absolutePath.includes("releasenotes")) { // If the file is in the releasenotes directory... + const split = fileName.split('-'); // split the file name where hyphenated... + // #todo, wait this should the slug should include all the words after the date, not just the first one. + return `releasenotes/${split[0]}/${split[1]}/${split[3]}${split[4]}` // and return a slug of releasenotes/YYYY/MM/slug + } return `${fileName}` // Otherwise, as long as there is a filename in GraphQL, use it as the slug. } @@ -127,7 +133,7 @@ exports.createPages = ({ graphql, actions }) => { { allDocs: allMdx( filter: { - fileAbsolutePath: { regex: "/content(?!/(partials|changelog|guides)/)/"} + fileAbsolutePath: { regex: "/content(?!/(partials|changelog|guides|releasenotes)/)/"} frontmatter: { draft: {ne: true} } @@ -297,35 +303,6 @@ exports.createPages = ({ graphql, actions }) => { }) }) - // Create guide pages. - const guides = result.data.allGuides.edges - guides.forEach(guide => { - if (guide.node.fields.guide_directory !== null) { - const previous = calculatePrevious(guide); - const next = calculateNext(guide); - const template = calculateTemplate(guide.node, "guide") - createPage({ - path: guide.node.fields.slug, - component: path.resolve(`./src/templates/${template}.js`), - context: { - slug: guide.node.fields.slug, - guide_directory: guide.node.fields.guide_directory, - previous, - next - }, - }) - } else { - const template = calculateTemplate(guide.node, "doc") - createPage({ - path: guide.node.fields.slug, - component: path.resolve(`./src/templates/${template}.js`), - context: { - slug: guide.node.fields.slug, - }, - }) - } - }) - // Create changelog pages. const changelogs = result.data.allChangelogs.edges changelogs.forEach(changelog => { @@ -360,21 +337,6 @@ exports.createPages = ({ graphql, actions }) => { }) - // Create Terminus Command pages - const terminusCommands = result.data.dataJson.commands - terminusCommands.forEach(command => { - const slugRegExp = /:/g - const slug = command.name.replace(slugRegExp, "-") - createPage({ - path: `terminus/commands/${slug}`, - component: path.resolve(`./src/templates/terminusCommand.js`), - context: { - slug: slug, - name: command.name - } - }) - }) - // Create changelog pagination. const postsPerPage = 6 const numPages = Math.ceil(changelogs.length / postsPerPage) @@ -398,14 +360,14 @@ exports.createPages = ({ graphql, actions }) => { // Create changelog pagination. const ReleaseNotesPerPage = 6 - const numberOfReleaseNotePages = Math.ceil(changelogs.length / ReleaseNotesPerPage) + const numberOfReleaseNotePages = Math.ceil(releaseNotes.length / ReleaseNotesPerPage) Array.from({ length: numberOfReleaseNotePages }).forEach((_, i) => { const currentPage = i + 1; const next = currentPage === 1 ? null : (currentPage === 2 ? `/release-notes/` : `/release-notes/page/${currentPage - 1}`); - const previous = currentPage < numberOfReleaseNotePages ? `/changelog/page/${currentPage + 1}` : null; + const previous = currentPage < numberOfReleaseNotePages ? `/release-notes/page/${currentPage + 1}` : null; createPage({ path: i === 0 ? `/release-notes/` : `/release-notes/page/${i + 1}`, - component: path.resolve("./src/templates/release-notes.js"), + component: path.resolve("./src/templates/releaseNotesListing.js"), context: { limit: ReleaseNotesPerPage, skip: i * ReleaseNotesPerPage, @@ -417,6 +379,26 @@ exports.createPages = ({ graphql, actions }) => { }) }) + // Create releasenotes pagination. + Array.from({ length: numPages }).forEach((_, i) => { + const currentPage = i + 1; + const next = currentPage === 1 ? null : (currentPage === 2 ? `/releasenotes/` : `/releasenotes/page/${currentPage - 1}`); + const previous = currentPage < numPages ? `/releasenotes/page/${currentPage + 1}` : null; + createPage({ + path: i === 0 ? `/releasenotes/` : `/releasenotes/page/${i + 1}`, + component: path.resolve("./src/templates/releaseNotesListing.js"), + context: { + limit: postsPerPage, + skip: i * postsPerPage, + numPages, + currentPage, + previous, + next + }, + }) + }) + + @@ -424,29 +406,7 @@ exports.createPages = ({ graphql, actions }) => { - // Create contributor pages. - const contributors = result.data.allContributorYaml.edges - contributors.forEach(contributor => { - createPage({ - path: `contributors/${contributor.node.yamlId}`, - component: path.resolve(`./src/templates/contributor.js`), - context: { - id: contributor.node.yamlId, - }, - }) - }) - // Create topics pages. - const topics = result.data.allLandingsYaml.edges - topics.forEach(topic => { - createPage({ - path: topic.node.path, - component: path.resolve(`./src/templates/landing.js`), - context: { - id: topic.node.id, - }, - }) - }) return null }) @@ -512,7 +472,7 @@ exports.onCreateNode = ({ node, getNode, actions }) => { } } - if (sourceInstanceName === 'changelogs') { + if (sourceInstanceName === 'changelogs' || sourceInstanceName === 'releasenotes') { const content = matter(node.internal.content, { excerpt: true, excerpt_separator: '' } ); const excerpt = content.excerpt || ""; diff --git a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md index 1597751f59..fb141c826e 100644 --- a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md +++ b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md @@ -6,3 +6,6 @@ publish_dated: "2023-11-02" # New Release Notes Structure Visibility into composer logs has been a top customer request. Now, if you need to debug a composer build failure due to an error, install the Terminus Composer Logs plugin on your machine to view more details. Upstream Update logs are also available. Installation instructions and command usage can be found here in the [plugin's GitHub repository](https://github.com/pantheon-systems/terminus-composer-logs-plugin). + + + diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index 18f5e7c433..a34f2b2899 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -86,6 +86,7 @@ class ChangelogsTemplate extends React.Component { render() { const changelogs = this.props.data.allMdx.edges + console.log(changelogs) return (
-

Pantheon Changelog

+

Pantheon Release Notes

Sign up for the Pantheon Changelog Newsletter to receive a @@ -117,7 +118,9 @@ class ChangelogsTemplate extends React.Component {

{changelogs.map((changelog) => ( + +
WHAT
Date: Thu, 14 Dec 2023 13:53:32 -0600 Subject: [PATCH 07/27] releaseNotesListing --- gatsby-node.js | 29 ---------------------------- src/templates/releaseNotesListing.js | 2 +- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index cb29cf7e21..8cc3c543ae 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -379,35 +379,6 @@ exports.createPages = ({ graphql, actions }) => { }) }) - // Create releasenotes pagination. - Array.from({ length: numPages }).forEach((_, i) => { - const currentPage = i + 1; - const next = currentPage === 1 ? null : (currentPage === 2 ? `/releasenotes/` : `/releasenotes/page/${currentPage - 1}`); - const previous = currentPage < numPages ? `/releasenotes/page/${currentPage + 1}` : null; - createPage({ - path: i === 0 ? `/releasenotes/` : `/releasenotes/page/${i + 1}`, - component: path.resolve("./src/templates/releaseNotesListing.js"), - context: { - limit: postsPerPage, - skip: i * postsPerPage, - numPages, - currentPage, - previous, - next - }, - }) - }) - - - - - - - - - - - return null }) } diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index a34f2b2899..8e396a794e 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -159,7 +159,7 @@ export const pageQuery = graphql` query Changelogs($skip: Int!, $limit: Int!) { allMdx( filter: { - fileAbsolutePath: { regex: "/changelogs/" } + fileAbsolutePath: { regex: "/releasenotes/" } frontmatter: { draft: { ne: true } } } sort: { fields: [fileAbsolutePath], order: DESC } From 1f7f50df981f1914d8c9d48f6ccd688b77ab62d2 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 14:00:54 -0600 Subject: [PATCH 08/27] bring back deleted stuff --- gatsby-node.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/gatsby-node.js b/gatsby-node.js index 8cc3c543ae..7b2c3bd0cc 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -303,6 +303,50 @@ exports.createPages = ({ graphql, actions }) => { }) }) + // Create guide pages. + const guides = result.data.allGuides.edges + guides.forEach(guide => { + if (guide.node.fields.guide_directory !== null) { + const previous = calculatePrevious(guide); + const next = calculateNext(guide); + const template = calculateTemplate(guide.node, "guide") + createPage({ + path: guide.node.fields.slug, + component: path.resolve(`./src/templates/${template}.js`), + context: { + slug: guide.node.fields.slug, + guide_directory: guide.node.fields.guide_directory, + previous, + next + }, + }) + } else { + const template = calculateTemplate(guide.node, "doc") + createPage({ + path: guide.node.fields.slug, + component: path.resolve(`./src/templates/${template}.js`), + context: { + slug: guide.node.fields.slug, + }, + }) + } + }) + + // Create Terminus Command pages + const terminusCommands = result.data.dataJson.commands + terminusCommands.forEach(command => { + const slugRegExp = /:/g + const slug = command.name.replace(slugRegExp, "-") + createPage({ + path: `terminus/commands/${slug}`, + component: path.resolve(`./src/templates/terminusCommand.js`), + context: { + slug: slug, + name: command.name + } + }) + }) + // Create changelog pages. const changelogs = result.data.allChangelogs.edges changelogs.forEach(changelog => { @@ -379,6 +423,31 @@ exports.createPages = ({ graphql, actions }) => { }) }) + + // Create contributor pages. + const contributors = result.data.allContributorYaml.edges + contributors.forEach(contributor => { + createPage({ + path: `contributors/${contributor.node.yamlId}`, + component: path.resolve(`./src/templates/contributor.js`), + context: { + id: contributor.node.yamlId, + }, + }) + }) + + // Create topics pages. + const topics = result.data.allLandingsYaml.edges + topics.forEach(topic => { + createPage({ + path: topic.node.path, + component: path.resolve(`./src/templates/landing.js`), + context: { + id: topic.node.id, + }, + }) + }) + return null }) } From ef9e33b8856a8e7e4d7f2ebc5a0cf0cbee97c2e5 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 14:12:50 -0600 Subject: [PATCH 09/27] more progress on release notes --- gatsby-node.js | 10 +++++++--- .../2023-11-02-terminus-composer-logs-plugin.md | 3 --- .../2023-12-31-new-release-notes-structure.md | 2 -- src/templates/releaseNote.js | 17 ++--------------- src/templates/releaseNotesListing.js | 5 ++++- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 7b2c3bd0cc..41d0d2f86b 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -35,7 +35,9 @@ const calculateSlug = (node, getNode) => { if (getNode(node.parent).absolutePath.includes("releasenotes")) { // If the file is in the releasenotes directory... const split = fileName.split('-'); // split the file name where hyphenated... // #todo, wait this should the slug should include all the words after the date, not just the first one. - return `releasenotes/${split[0]}/${split[1]}/${split[3]}${split[4]}` // and return a slug of releasenotes/YYYY/MM/slug + // set a const to remaining slug based on the keys from split that are not the date. + const remainingSlug = split.slice(3).join('-'); + return `releasenotes/${split[0]}/${split[1]}/${remainingSlug}` // and return a slug of releasenotes/YYYY/MM/slug } return `${fileName}` // Otherwise, as long as there is a filename in GraphQL, use it as the slug. @@ -402,7 +404,7 @@ exports.createPages = ({ graphql, actions }) => { }) }) - // Create changelog pagination. + // Create Release Note pagination. const ReleaseNotesPerPage = 6 const numberOfReleaseNotePages = Math.ceil(releaseNotes.length / ReleaseNotesPerPage) Array.from({ length: numberOfReleaseNotePages }).forEach((_, i) => { @@ -423,7 +425,6 @@ exports.createPages = ({ graphql, actions }) => { }) }) - // Create contributor pages. const contributors = result.data.allContributorYaml.edges contributors.forEach(contributor => { @@ -586,3 +587,6 @@ exports.onPreBootstrap = () => { fs.copySync(scriptsCopyFrom, scriptsCopyTo) } + + +/* todo should there be an error thrown if a release note category is set that is not allowed */ diff --git a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md index fb141c826e..3e6f02f80b 100644 --- a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md +++ b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md @@ -3,9 +3,6 @@ title: Terminus Composer Logs Plugin 1.0.0 Released publish_dated: "2023-11-02" --- -# New Release Notes Structure Visibility into composer logs has been a top customer request. Now, if you need to debug a composer build failure due to an error, install the Terminus Composer Logs plugin on your machine to view more details. Upstream Update logs are also available. Installation instructions and command usage can be found here in the [plugin's GitHub repository](https://github.com/pantheon-systems/terminus-composer-logs-plugin). - - diff --git a/source/releasenotes/2023-12-31-new-release-notes-structure.md b/source/releasenotes/2023-12-31-new-release-notes-structure.md index 08db16388e..5aea1aa516 100644 --- a/source/releasenotes/2023-12-31-new-release-notes-structure.md +++ b/source/releasenotes/2023-12-31-new-release-notes-structure.md @@ -3,8 +3,6 @@ title: New Release Notes Structure publish_dated: "2023-12-31" --- -# New Release Notes Structure - For nearly a decade, we have published a monthly "changelog" here within our Documentation site that summarizes significant changes to the platform. Going forward in 2024 we are changing some of the details of how we publish and organize this information. diff --git a/src/templates/releaseNote.js b/src/templates/releaseNote.js index 86394e0e92..9e3334dee6 100644 --- a/src/templates/releaseNote.js +++ b/src/templates/releaseNote.js @@ -85,23 +85,10 @@ class ChangelogTemplate extends React.Component {
- Pantheon Changelog + Pantheon Release Notes

{node.frontmatter.title}

-
-

- Sign up for the Pantheon Changelog Newsletter to receive a - monthly email on what's new and improved across the platform. -

- - Subscribe Now - - -
+
diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index 8e396a794e..80f6ad1443 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -102,6 +102,7 @@ class ChangelogsTemplate extends React.Component { Sign up for the Pantheon Changelog Newsletter to receive a monthly email on what's new and improved across the platform.

+ todo link to somewhere other than Pantheon learning.

( -
WHAT
+
HELLO
{changelog.node.frontmatter.title} + test {changelog.node.body} @@ -155,6 +157,7 @@ class ChangelogsTemplate extends React.Component { export default ChangelogsTemplate +/* todo remove draft filter from query */ export const pageQuery = graphql` query Changelogs($skip: Int!, $limit: Int!) { allMdx( From b382559c351439fa67a466bf5c197630f65f4a35 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 14:15:08 -0600 Subject: [PATCH 10/27] adding a note --- .../releasenotes/2023-11-02-terminus-composer-logs-plugin.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md index 3e6f02f80b..364708b784 100644 --- a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md +++ b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md @@ -6,3 +6,6 @@ publish_dated: "2023-11-02" Visibility into composer logs has been a top customer request. Now, if you need to debug a composer build failure due to an error, install the Terminus Composer Logs plugin on your machine to view more details. Upstream Update logs are also available. Installation instructions and command usage can be found here in the [plugin's GitHub repository](https://github.com/pantheon-systems/terminus-composer-logs-plugin). + + +TODO: Does this note belong in "action required?" Not every customer needs to do something. Only those who want to use the plugin. From 8a4d7e002d8e315e5d23c9cae79ce0fef06a7a8e Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 14:31:57 -0600 Subject: [PATCH 11/27] updates --- source/releasenotes/2023-08-18-php-security-updates.md | 9 +++++++++ .../releasenotes/2023-09-20-drupal-sa-core-2023-006.md | 9 +++++++++ source/releasenotes/2023-09-30-docs-design-system.md | 9 +++++++++ .../2023-10-31-front-end-sites-build-caching.md | 9 +++++++++ 4 files changed, 36 insertions(+) create mode 100644 source/releasenotes/2023-08-18-php-security-updates.md create mode 100644 source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md create mode 100644 source/releasenotes/2023-09-30-docs-design-system.md create mode 100644 source/releasenotes/2023-10-31-front-end-sites-build-caching.md diff --git a/source/releasenotes/2023-08-18-php-security-updates.md b/source/releasenotes/2023-08-18-php-security-updates.md new file mode 100644 index 0000000000..c68aed056a --- /dev/null +++ b/source/releasenotes/2023-08-18-php-security-updates.md @@ -0,0 +1,9 @@ +--- +title: "PHP Security Updates" +publish_dated: "2023-08-18" +--- + + +Pantheon has deployed PHP versions [8.2.9](https://www.php.net/ChangeLog-8.php#8.2.9), [8.1.22](https://www.php.net/ChangeLog-8.php#8.1.22), and [8.0.30](https://www.php.net/ChangeLog-8.php#8.0.30) to customer sites running on the platform. These releases address vulnerabilities disclosed in [CVE-2023-3823](https://nvd.nist.gov/vuln/detail/CVE-2023-3823) and [CVE-2023-3824](https://nvd.nist.gov/vuln/detail/CVE-2023-3824). + +If you are using PHP 8.2, 8.1 or 8.0, there is nothing further that you need to do. If you are still on PHP 7.4 or earlier, though, you should schedule some time to upgrade to a supported version.While the vulnerabilities patched in these latest releases are not reported to affect PHP 7.4, the fact remains that there could be (and probably are) unpatched vulnerabilities in the end-of-life versions. Read more about it in Greg Anderson’s [blog post](https://pantheon.io/blog/php-829-security-release-demonstrates-pantheons-commitment-protecting-your-sites). diff --git a/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md b/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md new file mode 100644 index 0000000000..fa8be8f92e --- /dev/null +++ b/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md @@ -0,0 +1,9 @@ +--- +title: "Drupal Security Update: SA Core 2023-006" +publish_dated: "2023-09-20" +--- + + +On September 20th, [Drupal core updates were released to address a critical vulnerability in the JSON:API module](https://status.pantheon.io/incidents/vj842n7k7w40). Those updates became immediately available within the Pantheon dashboard for one-click code updates. Additionally, [our engineers updated our CDN to mitigate potential attacks](https://status.pantheon.io/incidents/598zxv2v8l7p). + +If you have a Drupal site using JSON:API we suggest you update as soon as possible if you haven't done so already. And even if you aren't using JSON:API, it'll still feel good to apply an update, right? To better understand the nature of security updates, [come watch the Pantheon YouTube Livestream on October 25th](https://www.youtube.com/watch?v=WV2ZSeBOziU). diff --git a/source/releasenotes/2023-09-30-docs-design-system.md b/source/releasenotes/2023-09-30-docs-design-system.md new file mode 100644 index 0000000000..4cb3fffb13 --- /dev/null +++ b/source/releasenotes/2023-09-30-docs-design-system.md @@ -0,0 +1,9 @@ +--- +title: Documentation Site Updated with the Design System +publish_dated: "2023-09-30" +--- + + +We're excited to announce that our documentation site has been seamlessly integrated with our brand-new design system. This enhancement brings a fresh and cohesive look to our documentation, providing a unified and visually appealing experience for our users. Explore the updated, improved, and more accessible [Docs site](/) today. + +![Docs Design System](../images/DocsDesignSystem.png) diff --git a/source/releasenotes/2023-10-31-front-end-sites-build-caching.md b/source/releasenotes/2023-10-31-front-end-sites-build-caching.md new file mode 100644 index 0000000000..c57850e874 --- /dev/null +++ b/source/releasenotes/2023-10-31-front-end-sites-build-caching.md @@ -0,0 +1,9 @@ +--- +title: Front-End Build Site Caching +publish_dated: "2023-10-31" +--- + +Pantheon introduced a new build pipeline for Front End Sites to significantly improve build times. Beginning on November 13th, 2023, newly created sites are automatically using the new pipeline and cannot opt back to the old pipeline. Sites made prior to that date can opt-in to the new pipeline to take advantage of the new features. All pre-existing sites that do not opt-in will be switched over for new builds on or around January 15th. + +Additionally, we are adding support for Node 18 (for dynamic sites) and 20 (for both static and dynamic sites). To select a specific version, Pantheon is [moving away from using .nvmrc](/guides/decoupled/overview/manage-settings#nodejs-version) and will instead look to the [“engines” field](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#engines) in your project’s `package.json` file. + From 1c64f89d351ccccb4a83feee781a9239a7f12af4 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 14:34:29 -0600 Subject: [PATCH 12/27] release notes --- .../2023-08-08-pantheon-advanced-page-cache-1-4-1.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md diff --git a/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md b/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md new file mode 100644 index 0000000000..632c05cc4f --- /dev/null +++ b/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md @@ -0,0 +1,9 @@ +--- +title: "Pantheon Advanced Page Cache WordPress Plugin Updates" +publish_dated: "2023-08-08" +--- + + +We released an update for the [Pantheon Advanced Page Cache](https://wordpress.org/plugins/pantheon-advanced-page-cache/) WordPress plugin which adds a filter to allow disabling surrogate keys for posts' taxonomy terms. This can be especially helpful for posts with large numbers of taxonomies (such as WooCommerce products with a large number of global attributes). + +For more information, see [Pantheon documentation](/guides/wordpress-configurations/plugins#disable-surrogate-keys-for-taxonomy-terms). From a86b85e1c47da770357e5985762b5e32b725b18b Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 16:33:34 -0600 Subject: [PATCH 13/27] getting categories partially working --- gatsby-node.js | 3 ++- .../2023-11-02-terminus-composer-logs-plugin.md | 1 + .../releasenotes/2023-12-31-new-release-notes-structure.md | 7 ++++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 41d0d2f86b..64c11cb4b7 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -209,7 +209,8 @@ exports.createPages = ({ graphql, actions }) => { node { id frontmatter { - title + title, + categories } fields { slug diff --git a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md index 364708b784..e64946de44 100644 --- a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md +++ b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md @@ -9,3 +9,4 @@ Visibility into composer logs has been a top customer request. Now, if you need TODO: Does this note belong in "action required?" Not every customer needs to do something. Only those who want to use the plugin. +After discussion with Ingrid, no this would not get "Action required". because that should only be used for things that would disrupt. diff --git a/source/releasenotes/2023-12-31-new-release-notes-structure.md b/source/releasenotes/2023-12-31-new-release-notes-structure.md index 5aea1aa516..540328730f 100644 --- a/source/releasenotes/2023-12-31-new-release-notes-structure.md +++ b/source/releasenotes/2023-12-31-new-release-notes-structure.md @@ -1,6 +1,7 @@ --- title: New Release Notes Structure publish_dated: "2023-12-31" +categories: [security, anothercat] --- For nearly a decade, we have published a monthly "changelog" here within our Documentation site that summarizes significant changes to the platform. @@ -12,6 +13,6 @@ This switch will support more proactive communication and ensure that any notewo Here you will find: * A listing of all Release Notes at docs.pantheon.io/release-notes -* A listing of Release Notes by category like docs.pantheon.io/release-notes/infrastructure -* A month-by-month breakdown of all Release Notes like docs.pantheon.io/release-notes/all/2023-12 (todo or should it be docs.pantheon.io/release-notes/all/2023/12) -* A month-by-month breakdown of Release Notes by catetory and month like docs.pantheon.io/release-notes/infrastructure/2023-12 +* A listing of Release Notes by category (WordPress, Drupal, etc) like docs.pantheon.io/release-notes/infrastructure + + From 192086452f8cd20e742f376ab0ecdd75b50f60de Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 17:23:32 -0600 Subject: [PATCH 14/27] starting on a separate category component --- gatsby-node.js | 6 +- ...8-08-pantheon-advanced-page-cache-1-4-1.md | 2 +- .../2023-08-18-php-security-updates.md | 2 +- .../2023-09-20-drupal-sa-core-2023-006.md | 2 +- .../2023-09-30-docs-design-system.md | 2 +- ...023-10-31-front-end-sites-build-caching.md | 2 +- ...023-11-02-terminus-composer-logs-plugin.md | 2 +- .../2023-12-31-new-release-notes-structure.md | 2 +- src/components/releaseNoteCategories.js | 24 +++++++ src/templates/releaseNotesListing.js | 65 ++++++++++--------- 10 files changed, 72 insertions(+), 37 deletions(-) create mode 100644 src/components/releaseNoteCategories.js diff --git a/gatsby-node.js b/gatsby-node.js index 64c11cb4b7..d74e541f3b 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -210,7 +210,8 @@ exports.createPages = ({ graphql, actions }) => { id frontmatter { title, - categories + categories, + published_date } fields { slug @@ -524,6 +525,7 @@ exports.onCreateNode = ({ node, getNode, actions }) => { value: excerpt, }) + const textNode = { id: `${node.id}-MarkdownBody`, parent: node.id, @@ -591,3 +593,5 @@ exports.onPreBootstrap = () => { /* todo should there be an error thrown if a release note category is set that is not allowed */ +/* todo, infer published date from file name. And throw an error if there are files that don't follow the pattern. */ +/* todo, make a json file of allowed categories, description of the category, color name */ diff --git a/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md b/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md index 632c05cc4f..e9c4ad53f0 100644 --- a/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md +++ b/source/releasenotes/2023-08-08-pantheon-advanced-page-cache-1-4-1.md @@ -1,6 +1,6 @@ --- title: "Pantheon Advanced Page Cache WordPress Plugin Updates" -publish_dated: "2023-08-08" +published_date: "2023-08-08" --- diff --git a/source/releasenotes/2023-08-18-php-security-updates.md b/source/releasenotes/2023-08-18-php-security-updates.md index c68aed056a..eff44cf27d 100644 --- a/source/releasenotes/2023-08-18-php-security-updates.md +++ b/source/releasenotes/2023-08-18-php-security-updates.md @@ -1,6 +1,6 @@ --- title: "PHP Security Updates" -publish_dated: "2023-08-18" +published_date: "2023-08-18" --- diff --git a/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md b/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md index fa8be8f92e..c6e6cb29a7 100644 --- a/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md +++ b/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md @@ -1,6 +1,6 @@ --- title: "Drupal Security Update: SA Core 2023-006" -publish_dated: "2023-09-20" +published_date: "2023-09-20" --- diff --git a/source/releasenotes/2023-09-30-docs-design-system.md b/source/releasenotes/2023-09-30-docs-design-system.md index 4cb3fffb13..77b9335c2d 100644 --- a/source/releasenotes/2023-09-30-docs-design-system.md +++ b/source/releasenotes/2023-09-30-docs-design-system.md @@ -1,6 +1,6 @@ --- title: Documentation Site Updated with the Design System -publish_dated: "2023-09-30" +published_date: "2023-09-30" --- diff --git a/source/releasenotes/2023-10-31-front-end-sites-build-caching.md b/source/releasenotes/2023-10-31-front-end-sites-build-caching.md index c57850e874..4dc7f828b7 100644 --- a/source/releasenotes/2023-10-31-front-end-sites-build-caching.md +++ b/source/releasenotes/2023-10-31-front-end-sites-build-caching.md @@ -1,6 +1,6 @@ --- title: Front-End Build Site Caching -publish_dated: "2023-10-31" +published_date: "2023-10-31" --- Pantheon introduced a new build pipeline for Front End Sites to significantly improve build times. Beginning on November 13th, 2023, newly created sites are automatically using the new pipeline and cannot opt back to the old pipeline. Sites made prior to that date can opt-in to the new pipeline to take advantage of the new features. All pre-existing sites that do not opt-in will be switched over for new builds on or around January 15th. diff --git a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md index e64946de44..2ce0d8b346 100644 --- a/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md +++ b/source/releasenotes/2023-11-02-terminus-composer-logs-plugin.md @@ -1,6 +1,6 @@ --- title: Terminus Composer Logs Plugin 1.0.0 Released -publish_dated: "2023-11-02" +published_date: "2023-11-02" --- diff --git a/source/releasenotes/2023-12-31-new-release-notes-structure.md b/source/releasenotes/2023-12-31-new-release-notes-structure.md index 540328730f..441ba884eb 100644 --- a/source/releasenotes/2023-12-31-new-release-notes-structure.md +++ b/source/releasenotes/2023-12-31-new-release-notes-structure.md @@ -1,6 +1,6 @@ --- title: New Release Notes Structure -publish_dated: "2023-12-31" +published_date: "2023-12-31" categories: [security, anothercat] --- diff --git a/src/components/releaseNoteCategories.js b/src/components/releaseNoteCategories.js new file mode 100644 index 0000000000..959e9aa0ba --- /dev/null +++ b/src/components/releaseNoteCategories.js @@ -0,0 +1,24 @@ +import React from "react" + +const ReleaseNoteCategories = ({categories}) => { + +console.log(categories); + +if (!categories) { + return null +} + + return ( +
+ {categories.map((category, index) => ( +
+

{category}

+
+ )) + } +
+ + ) +} + +export default ReleaseNoteCategories diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index 80f6ad1443..221a963227 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -19,6 +19,7 @@ import SEO from "../layout/seo" import Enablement from "../components/enablement" import Color from "../components/color.js" import Download from "../components/download" +import ReleaseNoteCategories from "../components/releaseNoteCategories" import { @@ -32,7 +33,6 @@ import { Container, Icon, Pager, - SidebarLayout, } from "@pantheon-systems/pds-toolkit-react" const shortcodes = { @@ -87,6 +87,7 @@ class ChangelogsTemplate extends React.Component { render() { const changelogs = this.props.data.allMdx.edges console.log(changelogs) + console.log(changelogs[0].node.frontmatter.categories) return (

- -
-
-
-
- {changelogs.map((changelog) => ( - - -
HELLO
- -

- {changelog.node.frontmatter.title} -

- test - - - {changelog.node.body} - -
- ))} -
-
+
+
+
+ {changelogs.map((changelog) => ( + + + +
HELLO
+ +

+ {changelog.node.frontmatter.title} +

+ + + Todo, transform to date format

+ {changelog.node.frontmatter.published_date} + + Maybe + + + + + {changelog.node.body} + +
+ ))}
- - +
+ Date: Thu, 14 Dec 2023 17:38:38 -0600 Subject: [PATCH 15/27] more release notes cleanup --- .../2023-09-20-drupal-sa-core-2023-006.md | 1 + src/components/releaseNoteCategories.js | 8 +++++- src/templates/releaseNote.js | 26 ++++++------------- src/templates/releaseNotesListing.js | 1 - 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md b/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md index c6e6cb29a7..a82127adcf 100644 --- a/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md +++ b/source/releasenotes/2023-09-20-drupal-sa-core-2023-006.md @@ -1,6 +1,7 @@ --- title: "Drupal Security Update: SA Core 2023-006" published_date: "2023-09-20" +categories: [security] --- diff --git a/src/components/releaseNoteCategories.js b/src/components/releaseNoteCategories.js index 959e9aa0ba..e3135e517e 100644 --- a/src/components/releaseNoteCategories.js +++ b/src/components/releaseNoteCategories.js @@ -10,9 +10,15 @@ if (!categories) { return (
+{/* If there is one category display the singular form. */ + categories.length === 1 + ?

Category:

+ :

Categories:

+} + {categories.map((category, index) => (
-

{category}

+

{category}

)) } diff --git a/src/templates/releaseNote.js b/src/templates/releaseNote.js index 9e3334dee6..ed531080af 100644 --- a/src/templates/releaseNote.js +++ b/src/templates/releaseNote.js @@ -18,6 +18,7 @@ import SEO from "../layout/seo" import Enablement from "../components/enablement" import Color from "../components/color.js" import Download from "../components/download" +import ReleaseNoteCategories from "../components/releaseNoteCategories" import { @@ -44,7 +45,7 @@ const shortcodes = { // Set container width for search and main content. const containerWidth = "standard" -class ChangelogTemplate extends React.Component { +class ReleaseNoteTemplate extends React.Component { componentDidMount() { $("[data-toggle=popover]").popover({ trigger: "click", @@ -88,6 +89,7 @@ class ChangelogTemplate extends React.Component { Pantheon Release Notes

{node.frontmatter.title}

+
@@ -99,6 +101,7 @@ class ChangelogTemplate extends React.Component {
+ {node.body} @@ -106,22 +109,7 @@ class ChangelogTemplate extends React.Component {
- -
@@ -129,7 +117,7 @@ class ChangelogTemplate extends React.Component { } } -export default ChangelogTemplate +export default ReleaseNoteTemplate export const pageQuery = graphql` query ChangelogBySlug($slug: String!) { @@ -140,7 +128,9 @@ export const pageQuery = graphql` slug } frontmatter { - title + title, + published_date, + categories } } } diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index 221a963227..0493e38619 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -121,7 +121,6 @@ class ChangelogsTemplate extends React.Component { -
HELLO
Date: Thu, 14 Dec 2023 17:42:37 -0600 Subject: [PATCH 16/27] listing all --- src/templates/releaseNotesListing.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index 0493e38619..f4351c3ffb 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -57,7 +57,7 @@ const shortcodes = { const containerWidth = "standard" // Combined changelog template. -class ChangelogsTemplate extends React.Component { +class ReleaseNotesListingTemplate extends React.Component { componentDidMount() { $("[data-toggle=popover]").popover({ trigger: "click", @@ -159,19 +159,16 @@ class ChangelogsTemplate extends React.Component { } } -export default ChangelogsTemplate +export default ReleaseNotesListingTemplate /* todo remove draft filter from query */ export const pageQuery = graphql` - query Changelogs($skip: Int!, $limit: Int!) { + query Changelogs { allMdx( filter: { fileAbsolutePath: { regex: "/releasenotes/" } - frontmatter: { draft: { ne: true } } } sort: { fields: [fileAbsolutePath], order: DESC } - skip: $skip - limit: $limit ) { edges { node { From b2319aaebf0f7d86aa5736218c7cae98663caff2 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 18:09:14 -0600 Subject: [PATCH 17/27] category listing --- gatsby-node.js | 37 ++-- .../2023-12-31-new-release-notes-structure.md | 2 +- src/components/releaseNoteCategories.js | 11 +- src/templates/releaseNotesListing.js | 3 +- .../releaseNotesListingByCategory.js | 190 ++++++++++++++++++ 5 files changed, 226 insertions(+), 17 deletions(-) create mode 100644 src/templates/releaseNotesListingByCategory.js diff --git a/gatsby-node.js b/gatsby-node.js index d74e541f3b..fca7cc8428 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -406,27 +406,36 @@ exports.createPages = ({ graphql, actions }) => { }) }) - // Create Release Note pagination. - const ReleaseNotesPerPage = 6 - const numberOfReleaseNotePages = Math.ceil(releaseNotes.length / ReleaseNotesPerPage) - Array.from({ length: numberOfReleaseNotePages }).forEach((_, i) => { - const currentPage = i + 1; - const next = currentPage === 1 ? null : (currentPage === 2 ? `/release-notes/` : `/release-notes/page/${currentPage - 1}`); - const previous = currentPage < numberOfReleaseNotePages ? `/release-notes/page/${currentPage + 1}` : null; + // Create release notes without pagination. At a later date, we may want to add pagination. + // And can reused the code above. createPage({ - path: i === 0 ? `/release-notes/` : `/release-notes/page/${i + 1}`, + path: `/release-notes/`, component: path.resolve("./src/templates/releaseNotesListing.js"), + }) + + const allowedReleaseNoteCategories = { + "security": { + "Display Name": "Security", + "color": "red" + }, + "documentation": { + "Display Name": "Documentation", + "color": "purple" + }, + }; + + // Loop through all allowed categories and create a page for each one. + Object.keys(allowedReleaseNoteCategories).forEach((category) => { + createPage({ + path: `/release-notes/${category}`, + component: path.resolve("./src/templates/releaseNotesListingByCategory.js"), context: { - limit: ReleaseNotesPerPage, - skip: i * ReleaseNotesPerPage, - numberOfReleaseNotePages, - currentPage, - previous, - next + category: category, }, }) }) + // Create contributor pages. const contributors = result.data.allContributorYaml.edges contributors.forEach(contributor => { diff --git a/source/releasenotes/2023-12-31-new-release-notes-structure.md b/source/releasenotes/2023-12-31-new-release-notes-structure.md index 441ba884eb..4dc4cb5381 100644 --- a/source/releasenotes/2023-12-31-new-release-notes-structure.md +++ b/source/releasenotes/2023-12-31-new-release-notes-structure.md @@ -1,7 +1,7 @@ --- title: New Release Notes Structure published_date: "2023-12-31" -categories: [security, anothercat] +categories: [security, documentation] --- For nearly a decade, we have published a monthly "changelog" here within our Documentation site that summarizes significant changes to the platform. diff --git a/src/components/releaseNoteCategories.js b/src/components/releaseNoteCategories.js index e3135e517e..d9315937eb 100644 --- a/src/components/releaseNoteCategories.js +++ b/src/components/releaseNoteCategories.js @@ -1,4 +1,5 @@ import React from "react" +import { Link } from "gatsby" const ReleaseNoteCategories = ({categories}) => { @@ -18,7 +19,15 @@ if (!categories) { {categories.map((category, index) => (
-

{category}

+ + +

{category}

+ + + +
)) } diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index f4351c3ffb..ec5927e288 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -163,10 +163,11 @@ export default ReleaseNotesListingTemplate /* todo remove draft filter from query */ export const pageQuery = graphql` - query Changelogs { + query Changelogs($category: String!) { allMdx( filter: { fileAbsolutePath: { regex: "/releasenotes/" } + frontmatter: { categories: {eq: $category}} } sort: { fields: [fileAbsolutePath], order: DESC } ) { diff --git a/src/templates/releaseNotesListingByCategory.js b/src/templates/releaseNotesListingByCategory.js new file mode 100644 index 0000000000..e7436942b4 --- /dev/null +++ b/src/templates/releaseNotesListingByCategory.js @@ -0,0 +1,190 @@ +import React from "react" +import { graphql, Link } from "gatsby" +import { MDXRenderer } from "gatsby-plugin-mdx" +import { MDXProvider } from "@mdx-js/react" + +import Layout from "../layout/layout" +import NavButtons from "../components/navButtons" +import Callout from "../components/callout" +import Alert from "../components/alert" +import Accordion from "../components/accordion" +import ExternalLink from "../components/externalLink" +import Popover from "../components/popover" +import TabList from "../components/tabList" +import Tab from "../components/tab" +import TOC from "../components/toc" +import Card from "../components/card" +import CardGroup from "../components/cardGroup" +import SEO from "../layout/seo" +import Enablement from "../components/enablement" +import Color from "../components/color.js" +import Download from "../components/download" +import ReleaseNoteCategories from "../components/releaseNoteCategories" + + +import { + headline1, + headline2, + headline3, + headline4, +} from "../components/releaseHeadlines" + +import { + Container, + Icon, + Pager, +} from "@pantheon-systems/pds-toolkit-react" + +const shortcodes = { + Callout, + Alert, + Accordion, + ExternalLink, + Popover, + TabList, + Tab, + Card, + CardGroup, + Enablement, + Color, + Download, + h1: headline2, + h2: headline3, + h3: headline4, +} + +// Set container width for search and main content. +const containerWidth = "standard" + +// Combined changelog template. +class ReleaseNotesListingByCategoryTemplate extends React.Component { + componentDidMount() { + $("[data-toggle=popover]").popover({ + trigger: "click", + }) + + $("body").on("click", function (e) { + $('[data-toggle="popover"]').each(function () { + if ( + !$(this).is(e.target) && + $(this).has(e.target).length === 0 && + $(".popover").has(e.target).length === 0 + ) { + $(this).popover("hide") + } + }) + }) + + $("body").keyup(function (e) { + $('[data-toggle="popover"]').each(function () { + if (event.which === 27) { + $(this).popover("hide") + } + }) + }) + } + + render() { + const changelogs = this.props.data.allMdx.edges + console.log(changelogs) + console.log(changelogs[0].node.frontmatter.categories) + return ( + + +
+ +

Pantheon Release Notes

+
+
+
+
+
+ {changelogs.map((changelog) => ( + + + + +

+ {changelog.node.frontmatter.title} +

+ + + Todo, transform to date format

+ {changelog.node.frontmatter.published_date} + + Maybe + + + + + {changelog.node.body} + +
+ ))} +
+
+
+ + + +
+ + ) + } +} + +export default ReleaseNotesListingByCategoryTemplate + +/* todo remove draft filter from query */ +export const pageQuery = graphql` + query Changelogs($category: String!) { + allMdx( + filter: { + fileAbsolutePath: { regex: "/releasenotes/" } + frontmatter: { categories: {eq: $category}} + } + sort: { fields: [fileAbsolutePath], order: DESC } + ) { + edges { + node { + id + body + frontmatter { + title, + published_date, + categories, + } + fields { + slug + } + } + } + } + } +` From 3e0d46c137390aba12bd765212d9600f9e9c2ba8 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Thu, 14 Dec 2023 18:15:32 -0600 Subject: [PATCH 18/27] moar templating --- src/templates/releaseNotesListing.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index ec5927e288..f4351c3ffb 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -163,11 +163,10 @@ export default ReleaseNotesListingTemplate /* todo remove draft filter from query */ export const pageQuery = graphql` - query Changelogs($category: String!) { + query Changelogs { allMdx( filter: { fileAbsolutePath: { regex: "/releasenotes/" } - frontmatter: { categories: {eq: $category}} } sort: { fields: [fileAbsolutePath], order: DESC } ) { From 016065f585761f3baa9c6f7522a80ccdde38601e Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:04:20 -0600 Subject: [PATCH 19/27] getting tests passing --- src/templates/releaseNotesListing.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/templates/releaseNotesListing.js b/src/templates/releaseNotesListing.js index f4351c3ffb..11d6526236 100644 --- a/src/templates/releaseNotesListing.js +++ b/src/templates/releaseNotesListing.js @@ -91,8 +91,8 @@ class ReleaseNotesListingTemplate extends React.Component { return (
From 7e7e457750af69e64053716e8942b68fd5d76118 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:04:43 -0600 Subject: [PATCH 20/27] adding playwright examples --- tests/.github/workflows/playwright.yml | 27 ++ tests/.gitignore | 5 + tests/package-lock.json | 91 +++++ tests/package.json | 14 + tests/playwright.config.ts | 77 ++++ tests/tests-examples/demo-todo-app.spec.ts | 437 +++++++++++++++++++++ tests/tests/example.spec.ts | 19 + 7 files changed, 670 insertions(+) create mode 100644 tests/.github/workflows/playwright.yml create mode 100644 tests/.gitignore create mode 100644 tests/package-lock.json create mode 100644 tests/package.json create mode 100644 tests/playwright.config.ts create mode 100644 tests/tests-examples/demo-todo-app.spec.ts create mode 100644 tests/tests/example.spec.ts diff --git a/tests/.github/workflows/playwright.yml b/tests/.github/workflows/playwright.yml new file mode 100644 index 0000000000..90b6b700d4 --- /dev/null +++ b/tests/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000000..68c5d18f00 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/tests/package-lock.json b/tests/package-lock.json new file mode 100644 index 0000000000..36ee107cd4 --- /dev/null +++ b/tests/package-lock.json @@ -0,0 +1,91 @@ +{ + "name": "tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tests", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.40.1", + "@types/node": "^20.10.5" + } + }, + "node_modules/@playwright/test": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", + "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==", + "dev": true, + "dependencies": { + "playwright": "1.40.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", + "dev": true, + "dependencies": { + "playwright-core": "1.40.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 0000000000..9d001443e4 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,14 @@ +{ + "name": "tests", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.40.1", + "@types/node": "^20.10.5" + } +} diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts new file mode 100644 index 0000000000..301801ee1d --- /dev/null +++ b/tests/playwright.config.ts @@ -0,0 +1,77 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/tests/tests-examples/demo-todo-app.spec.ts b/tests/tests-examples/demo-todo-app.spec.ts new file mode 100644 index 0000000000..2fd6016fe8 --- /dev/null +++ b/tests/tests-examples/demo-todo-app.spec.ts @@ -0,0 +1,437 @@ +import { test, expect, type Page } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.goto('https://demo.playwright.dev/todomvc'); +}); + +const TODO_ITEMS = [ + 'buy some cheese', + 'feed the cat', + 'book a doctors appointment' +]; + +test.describe('New Todo', () => { + test('should allow me to add todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create 1st todo. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Make sure the list only has one todo item. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0] + ]); + + // Create 2nd todo. + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + + // Make sure the list now has two todo items. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[1] + ]); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); + + test('should clear text input field when an item is added', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create one todo item. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Check that input is empty. + await expect(newTodo).toBeEmpty(); + await checkNumberOfTodosInLocalStorage(page, 1); + }); + + test('should append new items to the bottom of the list', async ({ page }) => { + // Create 3 items. + await createDefaultTodos(page); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + // Check test using different methods. + await expect(page.getByText('3 items left')).toBeVisible(); + await expect(todoCount).toHaveText('3 items left'); + await expect(todoCount).toContainText('3'); + await expect(todoCount).toHaveText(/3/); + + // Check all items in one call. + await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); + await checkNumberOfTodosInLocalStorage(page, 3); + }); +}); + +test.describe('Mark all as completed', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test.afterEach(async ({ page }) => { + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should allow me to mark all items as completed', async ({ page }) => { + // Complete all todos. + await page.getByLabel('Mark all as complete').check(); + + // Ensure all todos have 'completed' class. + await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + }); + + test('should allow me to clear the complete state of all items', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + // Check and then immediately uncheck. + await toggleAll.check(); + await toggleAll.uncheck(); + + // Should be no completed classes. + await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); + }); + + test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + await toggleAll.check(); + await expect(toggleAll).toBeChecked(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Uncheck first todo. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').uncheck(); + + // Reuse toggleAll locator and make sure its not checked. + await expect(toggleAll).not.toBeChecked(); + + await firstTodo.getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Assert the toggle all is checked again. + await expect(toggleAll).toBeChecked(); + }); +}); + +test.describe('Item', () => { + + test('should allow me to mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + // Check first item. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').check(); + await expect(firstTodo).toHaveClass('completed'); + + // Check second item. + const secondTodo = page.getByTestId('todo-item').nth(1); + await expect(secondTodo).not.toHaveClass('completed'); + await secondTodo.getByRole('checkbox').check(); + + // Assert completed class. + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).toHaveClass('completed'); + }); + + test('should allow me to un-mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const firstTodo = page.getByTestId('todo-item').nth(0); + const secondTodo = page.getByTestId('todo-item').nth(1); + const firstTodoCheckbox = firstTodo.getByRole('checkbox'); + + await firstTodoCheckbox.check(); + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await firstTodoCheckbox.uncheck(); + await expect(firstTodo).not.toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 0); + }); + + test('should allow me to edit an item', async ({ page }) => { + await createDefaultTodos(page); + + const todoItems = page.getByTestId('todo-item'); + const secondTodo = todoItems.nth(1); + await secondTodo.dblclick(); + await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); + await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); + + // Explicitly assert the new text value. + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2] + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); +}); + +test.describe('Editing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should hide other controls when editing', async ({ page }) => { + const todoItem = page.getByTestId('todo-item').nth(1); + await todoItem.dblclick(); + await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); + await expect(todoItem.locator('label', { + hasText: TODO_ITEMS[1], + })).not.toBeVisible(); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should save edits on blur', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should trim entered text', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should remove the item if an empty text string was entered', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[2], + ]); + }); + + test('should cancel edits on escape', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); + await expect(todoItems).toHaveText(TODO_ITEMS); + }); +}); + +test.describe('Counter', () => { + test('should display the current number of todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + await expect(todoCount).toContainText('1'); + + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + await expect(todoCount).toContainText('2'); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); +}); + +test.describe('Clear completed button', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + }); + + test('should display the correct text', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); + }); + + test('should remove completed items when clicked', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).getByRole('checkbox').check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(todoItems).toHaveCount(2); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should be hidden when there are no items that are completed', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); + }); +}); + +test.describe('Persistence', () => { + test('should persist its data', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const todoItems = page.getByTestId('todo-item'); + const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); + await firstTodoCheck.check(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + + // Ensure there is 1 completed item. + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + // Now reload. + await page.reload(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + }); +}); + +test.describe('Routing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + // make sure the app had a chance to save updated todos in storage + // before navigating to a new view, otherwise the items can get lost :( + // in some frameworks like Durandal + await checkTodosInLocalStorage(page, TODO_ITEMS[0]); + }); + + test('should allow me to display active items', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await expect(todoItem).toHaveCount(2); + await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should respect the back button', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await test.step('Showing all items', async () => { + await page.getByRole('link', { name: 'All' }).click(); + await expect(todoItem).toHaveCount(3); + }); + + await test.step('Showing active items', async () => { + await page.getByRole('link', { name: 'Active' }).click(); + }); + + await test.step('Showing completed items', async () => { + await page.getByRole('link', { name: 'Completed' }).click(); + }); + + await expect(todoItem).toHaveCount(1); + await page.goBack(); + await expect(todoItem).toHaveCount(2); + await page.goBack(); + await expect(todoItem).toHaveCount(3); + }); + + test('should allow me to display completed items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Completed' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(1); + }); + + test('should allow me to display all items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await page.getByRole('link', { name: 'Completed' }).click(); + await page.getByRole('link', { name: 'All' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(3); + }); + + test('should highlight the currently applied filter', async ({ page }) => { + await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); + + //create locators for active and completed links + const activeLink = page.getByRole('link', { name: 'Active' }); + const completedLink = page.getByRole('link', { name: 'Completed' }); + await activeLink.click(); + + // Page change - active items. + await expect(activeLink).toHaveClass('selected'); + await completedLink.click(); + + // Page change - completed items. + await expect(completedLink).toHaveClass('selected'); + }); +}); + +async function createDefaultTodos(page: Page) { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } +} + +async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).length === e; + }, expected); +} + +async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e; + }, expected); +} + +async function checkTodosInLocalStorage(page: Page, title: string) { + return await page.waitForFunction(t => { + return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t); + }, title); +} diff --git a/tests/tests/example.spec.ts b/tests/tests/example.spec.ts new file mode 100644 index 0000000000..590f33f96c --- /dev/null +++ b/tests/tests/example.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('http://localhost:8000/release-notes'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Pantheon Release Notes/); +}); +/* +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +}); +*/ From 38ac5e6c90c84aa897271a312dc51b1ffb0f4b8e Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:06:59 -0600 Subject: [PATCH 21/27] Adding Playwright example --- {tests/.github => .github}/workflows/playwright.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {tests/.github => .github}/workflows/playwright.yml (100%) diff --git a/tests/.github/workflows/playwright.yml b/.github/workflows/playwright.yml similarity index 100% rename from tests/.github/workflows/playwright.yml rename to .github/workflows/playwright.yml From a2925c15604f314ade744bf556fa84a5fb691929 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:12:09 -0600 Subject: [PATCH 22/27] run in the correct dir --- .github/workflows/playwright.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 90b6b700d4..2f37ae175d 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,4 +1,7 @@ name: Playwright Tests +# todo, this GitHub Action should either be Triggered by Pantheon's build process +# phoning back to GitHub Actions after the deployment completes +# Or the GitHub Action will need to poll somehow that the deployment has completed. on: push: branches: [ main, master ] @@ -14,11 +17,11 @@ jobs: with: node-version: 18 - name: Install dependencies - run: npm ci + run: cd tests && npm ci - name: Install Playwright Browsers - run: npx playwright install --with-deps + run: cd tests && npx playwright install --with-deps - name: Run Playwright tests - run: npx playwright test + run: cd tests && npx playwright test - uses: actions/upload-artifact@v3 if: always() with: From d72f07d8e910aafb380c03a75e8c10896fecef29 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:25:38 -0600 Subject: [PATCH 23/27] hard-code url --- .github/workflows/playwright.yml | 2 ++ tests/tests/example.spec.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 2f37ae175d..1e92665cb1 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -2,6 +2,8 @@ name: Playwright Tests # todo, this GitHub Action should either be Triggered by Pantheon's build process # phoning back to GitHub Actions after the deployment completes # Or the GitHub Action will need to poll somehow that the deployment has completed. +# The Gatsby Build Process could place a file that reports that Git Hash that it was +# built from. Check that via polling. on: push: branches: [ main, master ] diff --git a/tests/tests/example.spec.ts b/tests/tests/example.spec.ts index 590f33f96c..67ea69a828 100644 --- a/tests/tests/example.spec.ts +++ b/tests/tests/example.spec.ts @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test'; test('has title', async ({ page }) => { - await page.goto('http://localhost:8000/release-notes'); + await page.goto('https://pr-8804-documentation.appa.pantheon.site/release-notes'); // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/Pantheon Release Notes/); From 073638dd773bb5f2d27ec0244b10ce76a2f3b1b7 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:33:39 -0600 Subject: [PATCH 24/27] setting base url as variable --- tests/playwright.config.ts | 2 +- tests/tests/example.spec.ts | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index 301801ee1d..87aa9d26fe 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -24,7 +24,7 @@ export default defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', + baseURL: process.env.GITHUB_PR_NUMBER ? 'https://pr-' + process.env.GITHUB_PR_NUMBER + '-documentation.appa.pantheon.site' : 'http://localhost:8000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', diff --git a/tests/tests/example.spec.ts b/tests/tests/example.spec.ts index 67ea69a828..3517fc36c5 100644 --- a/tests/tests/example.spec.ts +++ b/tests/tests/example.spec.ts @@ -1,19 +1,8 @@ import { test, expect } from '@playwright/test'; test('has title', async ({ page }) => { - await page.goto('https://pr-8804-documentation.appa.pantheon.site/release-notes'); + await page.goto('/release-notes'); // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/Pantheon Release Notes/); }); -/* -test('get started link', async ({ page }) => { - await page.goto('https://playwright.dev/'); - - // Click the get started link. - await page.getByRole('link', { name: 'Get started' }).click(); - - // Expects page to have a heading with the name of Installation. - await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); -}); -*/ From 09862cbb73a4f1318f0cab026a386ff9289c6347 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:34:36 -0600 Subject: [PATCH 25/27] need to handle building on main --- tests/playwright.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index 87aa9d26fe..7035c09bbd 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -24,6 +24,7 @@ export default defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ + // TODO, update this url to handle building on the main branch. baseURL: process.env.GITHUB_PR_NUMBER ? 'https://pr-' + process.env.GITHUB_PR_NUMBER + '-documentation.appa.pantheon.site' : 'http://localhost:8000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ From 2bcf7c144bd88f8a78e8a14619d98c671ab08bb7 Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:41:23 -0600 Subject: [PATCH 26/27] setting pr number --- .github/workflows/playwright.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 1e92665cb1..71513e00d4 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -5,10 +5,10 @@ name: Playwright Tests # The Gatsby Build Process could place a file that reports that Git Hash that it was # built from. Check that via polling. on: - push: - branches: [ main, master ] pull_request: branches: [ main, master ] +env: + GITHUB_PR_NUMBER: ${{ github.event.number }} jobs: test: timeout-minutes: 60 From 56112a773905055c8d278f3d5d92ad6abe727cec Mon Sep 17 00:00:00 2001 From: Steve Persch Date: Mon, 18 Dec 2023 13:45:34 -0600 Subject: [PATCH 27/27] fixing path for test reports --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 71513e00d4..3f536d633f 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -28,5 +28,5 @@ jobs: if: always() with: name: playwright-report - path: playwright-report/ + path: tests/playwright-report/ retention-days: 30