From 0a5c0c33e4d0f21ff43efeedad6e33d8395fe5ff Mon Sep 17 00:00:00 2001 From: Tabatha D Zeitke <47728020+tabathadelane@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:52:11 -0500 Subject: [PATCH] Feat: new EOL Comms pages (#18055) * feat: create EOL comms UI overview and template page * feat: add sort date option to eol feed * chore: add styling if eol date has passed * feat: create sortable table layout * chore: add PropTypes and clean up console errors * feat: add rss feed for eol posts * fix: remove console log * fix: remove check on function * feat(EOL): Added initial EOL content that's active and announced in Q2 (#18232) * feat(EOL): Added initial EOL content that's active and announced in Q2 * fix(Docs): Removed DNT tags * fix(Docs): Fixing some minor wording issues * chore(Docs): Removed placeholder content Goodbye Quenya! * fix(Docs): Responded to peer feedback * fix(Docs): Wanted to avoid using EOL in titles (#18273) got a PR approval from eng * add `

` tag for body and right padding * add sort direction * copy updates * chore: add EOL to nav * chore: comment out `

` for body * style(EOL): Changed short title to match title --------- Co-authored-by: Clark McAdoo Co-authored-by: Clark McAdoo <26727669+clarkmcadoo@users.noreply.github.com> Co-authored-by: Shawn Kilburn Co-authored-by: Sunny Zanchi --- gatsby-config.js | 2 +- gatsby-node.js | 3 + plugins/gatsby-plugin-eol-rss/gatsby-node.js | 126 ++++++++++ plugins/gatsby-plugin-eol-rss/package.json | 1 + .../docs-content-tools/i18n-exclusions.yml | 4 + scripts/utils/verify-mdx-utils.js | 1 + src/components/EolTable/EolTable.js | 44 ++++ src/components/EolTable/TableBody.js | 40 +++ src/components/EolTable/TableHeader.js | 95 +++++++ src/components/EolTable/index.js | 1 + src/content/eol/2024/04/eol-04-22-24.md | 52 ++++ .../eol/2024/04/eol-04-24-24-createtracer.md | 19 ++ .../eol/2024/04/eol-04-24-24-polling-api.md | 21 ++ src/content/eol/2024/08/eol-08-01-24.md | 97 +++++++ src/i18n/translations/en/translation.json | 13 +- src/nav/root.yml | 9 +- src/pages/eol.js | 221 ++++++++++++++++ src/templates/eolAnnouncement.js | 237 ++++++++++++++++++ src/utils/constants.js | 2 + 19 files changed, 975 insertions(+), 13 deletions(-) create mode 100644 plugins/gatsby-plugin-eol-rss/gatsby-node.js create mode 100644 plugins/gatsby-plugin-eol-rss/package.json create mode 100644 src/components/EolTable/EolTable.js create mode 100644 src/components/EolTable/TableBody.js create mode 100644 src/components/EolTable/TableHeader.js create mode 100644 src/components/EolTable/index.js create mode 100644 src/content/eol/2024/04/eol-04-22-24.md create mode 100644 src/content/eol/2024/04/eol-04-24-24-createtracer.md create mode 100644 src/content/eol/2024/04/eol-04-24-24-polling-api.md create mode 100644 src/content/eol/2024/08/eol-08-01-24.md create mode 100644 src/pages/eol.js create mode 100644 src/templates/eolAnnouncement.js diff --git a/gatsby-config.js b/gatsby-config.js index 9a040149a3f..db5bc9258ff 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -321,7 +321,7 @@ module.exports = { 'gatsby-plugin-release-note-rss', 'gatsby-plugin-whats-new-rss', 'gatsby-plugin-security-bulletins-rss', - + 'gatsby-plugin-eol-rss', 'gatsby-source-nav', 'gatsby-source-install-config', // https://www.gatsbyjs.com/plugins/gatsby-plugin-typegen/ diff --git a/gatsby-node.js b/gatsby-node.js index 75d7416e0ba..5e9350274d6 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -468,6 +468,9 @@ const getTemplate = (node) => { case fileRelativePath.includes('src/content/docs/release-notes'): return { template: 'releaseNote' }; + case fileRelativePath.includes('src/content/eol'): + return { template: 'eolAnnouncement' }; + case fileRelativePath.includes('src/content/whats-new'): return { template: 'whatsNew' }; diff --git a/plugins/gatsby-plugin-eol-rss/gatsby-node.js b/plugins/gatsby-plugin-eol-rss/gatsby-node.js new file mode 100644 index 00000000000..e945f41325e --- /dev/null +++ b/plugins/gatsby-plugin-eol-rss/gatsby-node.js @@ -0,0 +1,126 @@ +const fs = require('fs'); +const path = require('path'); +const RSS = require('rss'); +const format = require('date-fns/format'); +const parseISO = require('date-fns/parseISO'); +const unified = require('unified'); +const parse = require('rehype-parse'); +const addAbsoluteImagePath = require('../../rehype-plugins/utils/addAbsoluteImagePath'); +const rehypeStringify = require('rehype-stringify'); + +const eolQuery = async (graphql) => { + const query = ` + { + site { + siteMetadata { + title + siteUrl + } + } + allMarkdownRemark(filter: {fields: {slug: {regex: "/^/eol/"}}}) { + nodes { + frontmatter { + title + publishDate + eolEffectiveDate + summary + } + fields { + slug + } + htmlAst + } + } + } + `; + + const { data } = await graphql(query); + + return data; +}; + +const htmlParser = unified() + .use(parse) + .use(addAbsoluteImagePath) + .use(rehypeStringify); + +const getFeedItem = (node, siteMetadata) => { + const { + frontmatter, + fields: { slug }, + htmlAst, + } = node; + const { title, publishDate, summary } = frontmatter; + + const parsedHtml = htmlParser.runSync(htmlAst); + + // time is necessary for RSS validity + const date = parseISO(publishDate); + const pubDate = `${format(date, 'EE, dd LLL yyyy')} 00:00:00 +0000`; + const link = new URL(slug, siteMetadata.siteUrl).href; + const id = Buffer.from(`${publishDate}-${title}`).toString('base64'); + + return { + guid: id, + title, + custom_elements: [ + { link }, + { pubDate }, + { 'content:encoded': htmlParser.stringify(parsedHtml) }, + { description: summary ? summary : `ReleasedOn: ${pubDate}.` }, + ], + }; +}; + +const generateFeed = (publicDir, siteMetadata, reporter, eolNodes) => { + const title = `New Relic EOL`; + + let feedPath = path.join('eol', 'feed.xml'); + const buildLang = process.env.BUILD_LANG; + + // generate the XML at `/eol/feed.xml` for the i18n sites, + // otherwise they'll 404. + if (buildLang !== 'en') { + feedPath = path.join(buildLang, feedPath); + } + + // https://github.com/dylang/node-rss#feedoptions + const feedOptions = { + title, + feed_url: new URL(feedPath, siteMetadata.siteUrl).href, + site_url: siteMetadata.siteUrl, + }; + + reporter.info(`\t${feedOptions.feed_url}`); + + const feed = new RSS(feedOptions); + + eolNodes.nodes.map((node) => { + feed.item(getFeedItem(node, siteMetadata)); + }); + + const filepath = path.join(publicDir, feedPath); + const dir = path.dirname(filepath); + + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + + fs.writeFileSync(filepath, feed.xml()); +}; + +exports.onPostBuild = async ({ graphql, store, reporter }) => { + const { program } = store.getState(); + const publicDir = path.join(program.directory, 'public'); + + try { + reporter.info(`Generating XML for EOL RSS feed`); + const { site, allMarkdownRemark } = await eolQuery(graphql); + + generateFeed(publicDir, site.siteMetadata, reporter, allMarkdownRemark); + + reporter.info('\tDone!'); + } catch (error) { + reporter.panicOnBuild(`Unable to create EOL RSS feed: ${error}`, error); + } +}; diff --git a/plugins/gatsby-plugin-eol-rss/package.json b/plugins/gatsby-plugin-eol-rss/package.json new file mode 100644 index 00000000000..9e26dfeeb6e --- /dev/null +++ b/plugins/gatsby-plugin-eol-rss/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/scripts/actions/utils/docs-content-tools/i18n-exclusions.yml b/scripts/actions/utils/docs-content-tools/i18n-exclusions.yml index 498ffae3417..24d17874ea0 100644 --- a/scripts/actions/utils/docs-content-tools/i18n-exclusions.yml +++ b/scripts/actions/utils/docs-content-tools/i18n-exclusions.yml @@ -1,6 +1,7 @@ excludePath: ja-JP: - src/announcements + - src/content/eol - src/content/whats-new - src/content/docs/release-notes - src/content/docs/licenses @@ -25,6 +26,7 @@ excludePath: ko-KR: - src/announcements + - src/content/eol - src/content/whats-new - src/content/docs/release-notes - src/content/docs/licenses @@ -49,6 +51,7 @@ excludePath: es-LA: - src/announcements + - src/content/eol - src/content/whats-new - src/content/docs/release-notes - src/content/docs/licenses @@ -73,6 +76,7 @@ excludePath: pt-BR: - src/announcements + - src/content/eol - src/content/whats-new - src/content/docs/release-notes - src/content/docs/licenses diff --git a/scripts/utils/verify-mdx-utils.js b/scripts/utils/verify-mdx-utils.js index e4f664fbfca..1408ee0e0fb 100644 --- a/scripts/utils/verify-mdx-utils.js +++ b/scripts/utils/verify-mdx-utils.js @@ -86,6 +86,7 @@ const readFile = async (filePath) => { } const excludeFromFreshnessRegex = [ 'src/content/docs/release-notes/', + 'src/content/eol/', 'src/content/whats-new/', 'src/content/docs/style-guide/', 'src/content/docs/security/new-relic-security/security-bulletins/', diff --git a/src/components/EolTable/EolTable.js b/src/components/EolTable/EolTable.js new file mode 100644 index 00000000000..9c09bb7358d --- /dev/null +++ b/src/components/EolTable/EolTable.js @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { css } from '@emotion/react'; + +import TableBody from './TableBody'; +import TableHeader from './TableHeader'; + +const EolTable = ({ + body, + headers, + setSortDirection, + setSortField, + sortDirection, + sortField, +}) => { + return ( + <> + + + +
+ + ); +}; + +EolTable.propTypes = { + headers: PropTypes.arrayOf(PropTypes.object).isRequired, + body: PropTypes.arrayOf(PropTypes.object).isRequired, + sortField: PropTypes.string.isRequired, + setSortField: PropTypes.func.isRequired, +}; + +export default EolTable; diff --git a/src/components/EolTable/TableBody.js b/src/components/EolTable/TableBody.js new file mode 100644 index 00000000000..d4c920e8df2 --- /dev/null +++ b/src/components/EolTable/TableBody.js @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { css } from '@emotion/react'; + +const TableBody = ({ body, headers }) => { + return ( + + {body.map((content) => { + return ( + + {headers.map(({ contentId }) => { + return {content[contentId]}; + })} + + ); + })} + + ); +}; +TableBody.propTypes = { + headers: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.string.isRequired, + contentId: PropTypes.string.isRequired, + sort: PropTypes.bool, + }) + ).isRequired, + body: PropTypes.arrayOf( + PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.node])) + ).isRequired, +}; + +export default TableBody; diff --git a/src/components/EolTable/TableHeader.js b/src/components/EolTable/TableHeader.js new file mode 100644 index 00000000000..6dbdda20304 --- /dev/null +++ b/src/components/EolTable/TableHeader.js @@ -0,0 +1,95 @@ +import PropTypes from 'prop-types'; +import { css } from '@emotion/react'; + +import { Button, Icon } from '@newrelic/gatsby-theme-newrelic'; + +const TableHeader = ({ + headers, + setSortDirection, + setSortField, + sortDirection, + sortField, +}) => { + return ( + + + {headers.map(({ label, contentId, sort = false }) => { + const isActiveSort = sortField === contentId; + return ( + + {sort ? ( + + ) : ( + {label} + )} + + ); + })} + + + ); +}; + +TableHeader.propTypes = { + headers: PropTypes.arrayOf( + PropTypes.shape({ + label: PropTypes.string.isRequired, + contentId: PropTypes.string.isRequired, + sort: PropTypes.bool, + }) + ).isRequired, + sortField: PropTypes.string.isRequired, + setSortField: PropTypes.func.isRequired, +}; + +export const DIRECTION = { + ASC: 'asc', + DESC: 'desc', +}; +DIRECTION.opposite = (direction) => + direction === DIRECTION.ASC ? DIRECTION.DESC : DIRECTION.ASC; + +export default TableHeader; diff --git a/src/components/EolTable/index.js b/src/components/EolTable/index.js new file mode 100644 index 00000000000..5a147d3f0f7 --- /dev/null +++ b/src/components/EolTable/index.js @@ -0,0 +1 @@ +export { default } from './EolTable'; diff --git a/src/content/eol/2024/04/eol-04-22-24.md b/src/content/eol/2024/04/eol-04-22-24.md new file mode 100644 index 00000000000..d9de1a05501 --- /dev/null +++ b/src/content/eol/2024/04/eol-04-22-24.md @@ -0,0 +1,52 @@ +--- +title: "End of life for CPM and legacy synthetic monitoring runtimes" +summary: "On October 22, 2024, New Relic will end of life (EOL) the containerized private minion (CPM) capability and legacy synthetic monitoring runtimes, including our legacy Chrome 72 (or older) and Node version 10 (or older) runtimes." +publishDate: '2024-04-22' +eolEffectiveDate: '2024-10-22' +--- + +On October 22, 2024, New Relic will end of life (EOL): + +* The Containerized Private Minion (CPM) capability +* Legacy synthetic monitoring runtimes, including our legacy Chrome 72 (or older) and Node version 10 (or older) runtimes + +## What you need to do + +Update to the latest runtimes by [following procedures in our transition guide](https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/using-monitors/new-runtime/), or by contacting support. + +The new runtimes improve on our legacy runtime environment, including but not limited to these changes: + +* Updating to the new runtime will remove certain CVE findings that cannot be resolved due to the legacy runtime design and backward compatibility requirements of the Containerized Private Minion (CPM) +* Support for newer Chrome and Node.js versions, including easier upgrade paths +* More frequent browser version updates +* Access device emulation and other new capabilities + +**All customers must be on the new runtime by October 22, 2024 in order to prevent degradation.** + +Read on to learn more about how the update affects your public or private locations. + +### For public locations + +* New Relic will update all broken link and certificate check monitors to the new runtime. +* Customers should update their scripted API, scripted browser, and step monitors to the new runtime [using the runtime upgrade UI](https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/using-monitors/runtime-upgrade-ui) before October 22, 2024. + * If you do not update, we’ll force update your monitors to the new runtime on the end-of-life date. **This may result in check failures and triggered alerts.** + * Before updating to the new runtime, use the test results from the runtime upgrade UI to determine which monitors need to be modified. +* As of **August 26, 2024**, customers will be unable to create new monitors using legacy runtimes on public locations. + +### For private locations + +* You should [update to our new job manager](https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/private-locations/job-manager-transition-guide/), which provides support for our new runtime on private locations. **If you don't, your monitors will stop running at the end-of-life date.** +* Once you're using the new job manager, update your monitors to the new runtime using the runtime upgrade UI. This includes all non-ping monitor types. + * If you do not update, we'll force update your monitors to the new runtime. **This may result in check failures and triggered alerts.** + * Remember to use the test results from the runtime upgrade UI to determine the monitors that may require modifications before updating to the new runtime. +* On April 5, 2024, we added support for advanced features of the Containerized Private Minion (CPM) to the Synthetics Job Manager: + * Verified script execution (VSE) + * Custom environment variables + * Custom node modules +* Customers will be unable to create new monitors using legacy runtimes on private locations as of **August 26, 2024**. + +## Links to additional resources + +* [Runtime transition guide](https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/using-monitors/new-runtime/) +* [Runtime upgrade troubleshooting guide](https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/troubleshooting/runtime-upgrade-troubleshooting/) +* [Runtime upgrade UI documentation](https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/using-monitors/runtime-upgrade-ui) diff --git a/src/content/eol/2024/04/eol-04-24-24-createtracer.md b/src/content/eol/2024/04/eol-04-24-24-createtracer.md new file mode 100644 index 00000000000..2b77758ac0a --- /dev/null +++ b/src/content/eol/2024/04/eol-04-24-24-createtracer.md @@ -0,0 +1,19 @@ +--- +title: "End of life for the browser monitoring `createTracer()` API call" +summary: "We're end-of-lifing this API call, because it's blocking our ability to update and improve the browser SPA agent." +publishDate: '2024-04-24' +eolEffectiveDate: '2024-10-15' +--- + +On October 15, 2024, New Relic will end of life the browser monitoring `createTracer()` API call. + +New Relic is updating the browser SPA agent to be more performant, with improved accuracy and fewer lines of code. These updates simplify the agent, letting customers diagnose issues with their browser apps more easily. Before New Relic can update the browser SPA agent, we need to remove the `createTracer()` API. + +Accounts using the `createTracer()` API at the time of end of life will lose performance metrics about their SPAs. + +## What you need to do + +We recommend that you migrate to the `addPageAction()` API call to collect time data about sub-components on your pages. + +See our doc on [`addPageAction`](https://docs.newrelic.com/docs/browser/new-relic-browser/browser-apis/addpageaction/) for information on how to implement this API call. + diff --git a/src/content/eol/2024/04/eol-04-24-24-polling-api.md b/src/content/eol/2024/04/eol-04-24-24-polling-api.md new file mode 100644 index 00000000000..a4cc28e1b21 --- /dev/null +++ b/src/content/eol/2024/04/eol-04-24-24-polling-api.md @@ -0,0 +1,21 @@ +--- +title: "End of life for Azure SQL database integration polling API" +summary: "Azure is deprecating the SDK the polling API uses and will no longer be providing critical updates to this API, creating security concerns moving forward." +publishDate: '2024-04-22' +eolEffectiveDate: '2024-12-01' +--- + +On December 1, 2024, New Relic will end support for the Azure SQL database integration polling API, because Azure is deprecating the SDK that the polling API uses. You don't need to take action unless you capture data with the polling API and you're using the Azure SQL Database integration. + +## What you need to do + +If you’re using the Polling API to report data to the Azure SQL Database integration, we recommend that you migrate to the Azure Monitor integration. + +You can access the Azure monitoring integration by going to **one.newrelic.com > Infrastructure > Azure**. Once you’ve enabled the Azure monitoring integration, go to **Limit resource types** and set it to **microsoft.Sql/servers/databases**. + +If you have alerts or dashboards that use metrics from the Azure SQL database monitoring polling API, replace them with metrics from the Azure monitoring integration. + +## Links to additional resources + +For more on the New Relic Azure monitor integration, [see our docs](https://docs.newrelic.com/docs/infrastructure/microsoft-azure-integrations/azure-integrations-list/azure-monitor/). + diff --git a/src/content/eol/2024/08/eol-08-01-24.md b/src/content/eol/2024/08/eol-08-01-24.md new file mode 100644 index 00000000000..fd9e291052f --- /dev/null +++ b/src/content/eol/2024/08/eol-08-01-24.md @@ -0,0 +1,97 @@ +--- +title: "End of life for Google Core Web Vital FID metric" +summary: "On September 9, 2024, Google is deprecating the FID metric, in favor of Interaction to Next Paint (“INP”)." +publishDate: '2024-08-01' +eolEffectiveDate: '2024-09-09' +--- + +On September 9, 2024, [Google is deprecating the FID metric](https://developers.google.com/search/blog/2023/05/introducing-inp), in favor of Interaction to Next Paint (“INP”). Since New Relic uses certain libraries and APIs that leverage the FID metric, you will need to take the actions below before September 9, 2024 to avoid inaccurate or unexpected behavior with custom dashboards, alerts, and service level reporting. + +## What you need to do + +To avoid inaccurate alerts, charts, and service levels, you must make the following changes **before September 9, 2024**: + +1. Edit all **custom dashboards** using FID from the `PageViewTiming` event and replace with INP. +2. Edit any NRQL **alert conditions** using FID from the `PageViewTiming` event and replace with INP. +3. Edit any **Service Levels** using FID from the PageViewTiming event and replace with INP. + +See the resources below for more information on how to identify which dashboards, alerts, and service levels use the FID metric. + +Additionally, if you're using copy/paste browser instrumentation or are pinned to a version prior to [version 1227](https://docs.newrelic.com/docs/release-notes/new-relic-browser-release-notes/browser-agent-release-notes/browser-agent-v1227/), you must update the browser agent to version 1227 or higher to ensure that you have access to using the INP metric. To check which browser agent version you're on and for instructions on how to update your agent, please [see our documentation](https://docs.newrelic.com/docs/browser/new-relic-browser/installation/update-browser-agent/). If you're using version 1227 or higher, you do not need to update your browser agent for this EOL; however, we recommend that customers keep all agents up to date. + +## Additional resources + +Customers can use the following queries (either NRQL or via NerdGraph) to identify custom dashboards, alerts, and service levels that use the FID metric. + +### Custom dashboards + +Use the [`NrdbQuery` event](https://docs-preview.newrelic.com/docs/query-based-pricing#custom-query) query to find whether FID is being used in a custom dashboard. + +`SELECT uniques(source.dashboardId) FROM NrdbQuery WHERE query like '%firstInputDelay%' SINCE THIS WEEK` + +### Alerts + +Use the following [alerts-specific NerdGraph query](https://docs.newrelic.com/docs/apis/nerdgraph/get-started/introduction-new-relic-nerdgraph/) in your account to find whether FID is being used in a NRQL alert condition. + +``` +{ + actor { + account(id: {account-id}) { + alerts { + nrqlConditionsSearch(searchCriteria: {queryLike: "firstInputDelay"}) { + nextCursor + nrqlConditions { + id + name + nrql { + query + } + } + } + } + } + } +} +``` + +### Service Levels + +Use the following [browser monitoring and Service Levels-specific NerdGraph](https://docs.newrelic.com/docs/apis/nerdgraph/get-started/introduction-new-relic-nerdgraph/) queries in your account to determine which SLIs are affected: + +1. Get the GUID of all the browser monitoring apps that have SLIs: + +``` +{ + actor { + entitySearch( + query: "domain = 'BROWSER' AND type = 'APPLICATION' AND `tags.nr.has_slis` = 'true'" + ) { + results { + entities { + guid + } + } + } + } +} +``` + +2. For each of these browser monitoring apps, get the list of SLIs and check if in the `WHERE` clause of the query there is a reference to `firstInputDelay`: + +``` +{ + actor { + entity(guid: "") { + serviceLevel { + indicators { + events { + validEvents { + where + } + } + } + } + } + } +} +``` diff --git a/src/i18n/translations/en/translation.json b/src/i18n/translations/en/translation.json index bfe79a657aa..2957d88708d 100644 --- a/src/i18n/translations/en/translation.json +++ b/src/i18n/translations/en/translation.json @@ -26,17 +26,14 @@ "whatsNew": { "title": "What's new in New Relic" }, + "eol": { + "title": "End-of-life announcements" + }, "home": { "pageTitle": "Welcome to New Relic docs!", "search": { "popularSearches": { - "options": [ - "NRQL", - "logs", - "alert", - "best practices", - "Kubernetes" - ], + "options": ["NRQL", "logs", "alert", "best practices", "Kubernetes"], "title": "Popular searches" }, "placeholder": "Search" @@ -361,4 +358,4 @@ "freeTextQuestion": "Is there anything that you would change about New Relic docs? If so, please tell us what and why." } } -} \ No newline at end of file +} diff --git a/src/nav/root.yml b/src/nav/root.yml index 7edb7d298b7..e6031683839 100644 --- a/src/nav/root.yml +++ b/src/nav/root.yml @@ -54,16 +54,18 @@ pages: path: nrql - title: Service Level Management path: service-level-management - - title: Security + - title: Security - title: New Relic IAST - path: iast + path: iast - title: Vulnerability Management - path: vuln-management + path: vuln-management - title: Latest updates - title: Release notes path: release-notes - title: What's new? path: whats-new + - title: End-of-life announcements + path: /eol - title: Admin and data - title: Account & user management path: accounts @@ -75,4 +77,3 @@ pages: path: new-relic-security - title: Licenses path: licenses - diff --git a/src/pages/eol.js b/src/pages/eol.js new file mode 100644 index 00000000000..361654afc9a --- /dev/null +++ b/src/pages/eol.js @@ -0,0 +1,221 @@ +import React, { useMemo, useState } from 'react'; +import PropTypes from 'prop-types'; +import { css } from '@emotion/react'; +import { graphql } from 'gatsby'; +import { + Layout, + Icon, + Link, + useTranslation, +} from '@newrelic/gatsby-theme-newrelic'; +import EolTable from '../components/EolTable'; +import { DIRECTION } from '../components/EolTable/TableHeader'; +import PageTitle from '../components/PageTitle'; +import SEO from '../components/SEO'; +import ErrorBoundary from '../components/ErrorBoundary'; +import { TYPES } from '../utils/constants'; + +// @tw: add any body content here. +// it will go under the main heading and above the EOL timeline. +// const body = ( +// <> +//

+// 🤠 howdy. here is a link +//

+// +// ); +const body = ''; + +const SORT_BY_FIELDS = { + PUBLISH_DATE: 'publishDate', + EOL_DATE: 'eolDate', +}; + +const Eol = ({ data, location }) => { + const [sortDirection, setSortDirection] = useState(DIRECTION.ASC); + const [sortField, setSortField] = useState(SORT_BY_FIELDS.PUBLISH_DATE); + const now = useMemo(() => new Date(), []); + const { queryByEOLDate, queryByPublishDate } = data; + + const tableHeaders = [ + { label: 'Published', contentId: 'publishDate', sort: true }, + { label: 'EOL effective', contentId: 'eolDate', sort: true }, + { label: '', contentId: 'details' }, + ]; + + const shapePostData = (posts) => + posts.edges.map((post) => { + const { frontmatter } = post.node; + const eolDate = new Date(frontmatter.eolEffectiveDate); + const passedEOL = now > eolDate; + + return { + id: post.node.id, + publishDate: frontmatter.publishDate, + eolDate: frontmatter.eolEffectiveDate, + details: ( +
+ + {frontmatter.title} + +

+ {frontmatter.summary} +

+
+ ), + }; + }); + + const postsByPublish = shapePostData(queryByPublishDate); + const postsByEOL = shapePostData(queryByEOLDate); + + if (sortDirection === DIRECTION.DESC) { + postsByPublish.reverse(); + postsByEOL.reverse(); + } + + const postsByDate = { + publishDate: postsByPublish, + eolDate: postsByEOL, + }; + + if (typeof window !== 'undefined' && typeof newrelic === 'object') { + window.newrelic.setCustomAttribute('pageType', 'Dynamic/Eol'); + } + + const { t } = useTranslation(); + + return ( + + +
+ :first-child { + margin-right: 0.5rem; + } + } + `} + > + {t('strings.eol.title')} + + RSS + + + + + {body} + + +
+
+ ); +}; + +Eol.propTypes = { + data: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, +}; + +export const pageQuery = graphql` + query { + queryByPublishDate: allMarkdownRemark( + sort: { + fields: [frontmatter___publishDate, frontmatter___title] + order: [DESC, ASC] + } + filter: { fields: { slug: { regex: "/^/eol/" } } } + ) { + edges { + node { + id + frontmatter { + title + summary + eolEffectiveDate(formatString: "MMMM D, YYYY") + publishDate(formatString: "MMMM D, YYYY") + } + fields { + slug + } + } + } + } + queryByEOLDate: allMarkdownRemark( + sort: { + fields: [frontmatter___eolEffectiveDate, frontmatter___title] + order: [DESC, ASC] + } + filter: { fields: { slug: { regex: "/^/eol/" } } } + ) { + edges { + node { + id + frontmatter { + title + summary + eolEffectiveDate(formatString: "MMMM D, YYYY") + publishDate(formatString: "MMMM D, YYYY") + } + fields { + slug + } + } + } + } + } +`; + +export default Eol; diff --git a/src/templates/eolAnnouncement.js b/src/templates/eolAnnouncement.js new file mode 100644 index 00000000000..6400a8decca --- /dev/null +++ b/src/templates/eolAnnouncement.js @@ -0,0 +1,237 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { css } from '@emotion/react'; +import { graphql } from 'gatsby'; +import { + Icon, + Layout, + Link, + MarkdownContainer, + ContributingGuidelines, +} from '@newrelic/gatsby-theme-newrelic'; +import SEO from '../components/SEO'; +import PageTitle from '../components/PageTitle'; +import { TYPES } from '../utils/constants'; +import ErrorBoundary from '../components/ErrorBoundary'; + +const EolAnnouncement = ({ data, location, pageContext }) => { + const { + site: { + siteMetadata: { siteUrl }, + }, + markdownRemark: { + html, + frontmatter: { + title, + summary, + eolEffectiveDate, + publishDate, + learnMoreLink, + }, + fields: { fileRelativePath }, + }, + } = data; + + const { disableSwiftype } = pageContext; + + if (typeof window !== 'undefined' && typeof newrelic === 'object') { + window.newrelic.setCustomAttribute('pageType', 'Template/eol'); + } + + return ( + + + + {title} + +
+
+ + + Published: + + {publishDate} +
+
+ + + End of life effective: + + {eolEffectiveDate} +
+ +
+

{summary}

+ {learnMoreLink && ( +
    li { + margin: 0; + } + + @supports not (gap: 1rem) { + > li:not(:last-child) { + margin-right: 1rem; + } + } + `} + > +
  • + + Learn more + +
  • +
+ )} +
+
+ + + * { + justify-content: flex-start; + text-align: left; + } + `} + fileRelativePath={fileRelativePath} + issueLabels={['feedback', 'feedback-issue']} + /> + +
+ ); +}; + +EolAnnouncement.propTypes = { + data: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + pageContext: PropTypes.object.isRequired, +}; + +export const pageQuery = graphql` + query($slug: String!) { + site { + siteMetadata { + siteUrl + } + } + markdownRemark(fields: { slug: { eq: $slug } }) { + html + frontmatter { + title + eolEffectiveDate(formatString: "MMMM D, YYYY") + publishDate(formatString: "MMMM D, YYYY") + summary + learnMoreLink + } + fields { + fileRelativePath + } + } + } +`; + +const MetaLink = ({ children, to, siteUrl }) => { + const isExternalLink = to.startsWith('http') && !to.startsWith(siteUrl); + + return ( + + {children}{' '} + {isExternalLink && ( + + )} + + ); +}; + +MetaLink.propTypes = { + children: PropTypes.node.isRequired, + to: PropTypes.string.isRequired, + siteUrl: PropTypes.string.isRequired, +}; + +export default EolAnnouncement; diff --git a/src/utils/constants.js b/src/utils/constants.js index 08e03695e73..e6d657fb37f 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -7,12 +7,14 @@ export const TYPES = { LANDING_PAGE: 'term_page_landing_page', RELEASE_NOTE: 'release_notes', WHATS_NEW: 'nr1_announcement', + EOL: 'nr1_announcement', ATTRIBUTE_DEFINITION: 'attribute_definition', EVENT_DEFINITION: 'event_definition', API_LANDING_PAGE: 'term_page_api_menu', TABLE_OF_CONTENTS: 'views_page_menu', AUTO_INDEX_PAGE: 'views_page_menu', WHATS_NEW_PAGE: 'views_page_content', + EOL_PAGE: 'views_page_content', INTERACTIVE_INSTALL_PAGE: 'interactive_install_page', };