Skip to content

Commit

Permalink
Feat: new EOL Comms pages (#18055)
Browse files Browse the repository at this point in the history
* 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 `<p>` tag for body and right padding

* add sort direction

* copy updates

* chore: add EOL to nav

* chore: comment out `<p>` for body

* style(EOL): Changed short title to match title

---------

Co-authored-by: Clark McAdoo <[email protected]>
Co-authored-by: Clark McAdoo <[email protected]>
Co-authored-by: Shawn Kilburn <[email protected]>
Co-authored-by: Sunny Zanchi <[email protected]>
  • Loading branch information
5 people authored Aug 14, 2024
1 parent d735b15 commit 0a5c0c3
Show file tree
Hide file tree
Showing 19 changed files with 975 additions and 13 deletions.
2 changes: 1 addition & 1 deletion gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
3 changes: 3 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' };

Expand Down
126 changes: 126 additions & 0 deletions plugins/gatsby-plugin-eol-rss/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -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 `<lang>/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);
}
};
1 change: 1 addition & 0 deletions plugins/gatsby-plugin-eol-rss/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
4 changes: 4 additions & 0 deletions scripts/actions/utils/docs-content-tools/i18n-exclusions.yml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions scripts/utils/verify-mdx-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/',
Expand Down
44 changes: 44 additions & 0 deletions src/components/EolTable/EolTable.js
Original file line number Diff line number Diff line change
@@ -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 (
<>
<table
css={css`
padding-right: 4rem;
width: 100%;
`}
>
<TableHeader
headers={headers}
sortDirection={sortDirection}
sortField={sortField}
setSortDirection={setSortDirection}
setSortField={setSortField}
/>
<TableBody headers={headers} body={body} />
</table>
</>
);
};

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;
40 changes: 40 additions & 0 deletions src/components/EolTable/TableBody.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';

const TableBody = ({ body, headers }) => {
return (
<tbody
css={css`
tr {
vertical-align: top;
border: 2px solid grey;
}
`}
>
{body.map((content) => {
return (
<tr key={content.id}>
{headers.map(({ contentId }) => {
return <td key={contentId}>{content[contentId]}</td>;
})}
</tr>
);
})}
</tbody>
);
};
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;
95 changes: 95 additions & 0 deletions src/components/EolTable/TableHeader.js
Original file line number Diff line number Diff line change
@@ -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 (
<thead
css={css`
margin-bottom: 2rem;
th {
text-align: left;
}
`}
>
<tr>
{headers.map(({ label, contentId, sort = false }) => {
const isActiveSort = sortField === contentId;
return (
<th key={contentId}>
{sort ? (
<Button
variant={Button.VARIANT.PLAIN}
onClick={() => {
if (sortField === contentId) {
setSortDirection(DIRECTION.opposite(sortDirection));
} else {
setSortField(contentId);
setSortDirection(DIRECTION.ASC);
}
}}
css={css`
background: none;
`}
>
<b
css={css`
margin: 0 0.25rem;
`}
>
{label}
</b>
<Icon
name={
isActiveSort && sortDirection === DIRECTION.DESC
? 'fe-arrow-up'
: 'fe-arrow-down'
}
size="1rem"
css={css`
position: relative;
top: 1px;
stroke: ${isActiveSort ? '#00ac69' : 'grey'};
stroke-width: 4px;
`}
/>
</Button>
) : (
<b>{label}</b>
)}
</th>
);
})}
</tr>
</thead>
);
};

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;
1 change: 1 addition & 0 deletions src/components/EolTable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './EolTable';
Loading

0 comments on commit 0a5c0c3

Please sign in to comment.