Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update v9.3.0 (upstream update from FTW-daily v8.6.0) #148

Merged
merged 45 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
43d43a9
Bump minimist from 1.2.0 to 1.2.6
dependabot[bot] Mar 23, 2022
dc879de
Bump moment from 2.29.1 to 2.29.2
dependabot[bot] Apr 9, 2022
94c3d08
Bump async from 2.6.3 to 2.6.4
dependabot[bot] Apr 28, 2022
95c2568
Merge pull request #1503 from sharetribe/dependabot/npm_and_yarn/mini…
Gnito May 17, 2022
57b0ad3
Merge pull request #1506 from sharetribe/dependabot/npm_and_yarn/mome…
Gnito May 17, 2022
9477e59
Merge pull request #1509 from sharetribe/dependabot/npm_and_yarn/asyn…
Gnito May 17, 2022
6690c6a
Update array-includes 3.1.4 > 3.1.5
Gnito May 17, 2022
596d403
Update final-form 4.20.4 > 4.20.7
Gnito May 17, 2022
24549bc
Update react-final-form 6.5.7 > 6.5.9
Gnito May 17, 2022
4230473
Update inquirer 8.2.0 > 8.2.4
Gnito May 17, 2022
aec2686
Update moment 2.29.2 > 2.29.3
Gnito May 17, 2022
cc3fd72
Update nodemon 2.9.15 > 2.0.16
Gnito May 17, 2022
c16881c
Update path-to-regexp 6.2.0 > 6.2.1
Gnito May 17, 2022
44570c4
Update react-helmet-async 1.1.2 > 1.3.0
Gnito May 17, 2022
3cfc833
Update react-intl 5.22.0 > 5.25.1
Gnito May 17, 2022
ccba08b
Update query-string 7.0.1 > 7.1.1
Gnito May 17, 2022
d11a855
Update body-parser 1.19.0 > 1.20.0
Gnito May 17, 2022
3b2521f
Update array.prototype.find 2.1.2 > 2.2.0
Gnito May 17, 2022
f3f6dde
Update prop-types 15.7.2 > 15.8.1
Gnito May 17, 2022
e89826d
Update express 4.17.1 > 4.18.1
Gnito May 17, 2022
7759b9e
Update passport 0.5.0 > 0.5.3
Gnito May 17, 2022
44131c5
Update core-js 3.19.2 > 3.22.5
Gnito May 17, 2022
5517609
Update sentry libs 6.15.0 > 6.19.7
Gnito May 17, 2022
dfb2613
Update concurrently 6.4.0 > 7.2.0
Gnito May 17, 2022
83cf559
canuse-lite db was outdated
Gnito May 17, 2022
375898c
Update @babel/runtime 7.16.3 > 7.17.9
Gnito May 17, 2022
298bcab
Update jose 3.11.4 > 3.20.3
Gnito May 17, 2022
6661e10
Update jose 3.20.3 > 4.8.1
Gnito May 17, 2022
13e539a
Update node env in CI for concurrently lib
Gnito May 17, 2022
1d0b4e5
Update react-router-dom 5.2.0 > 5.3.2
Gnito May 18, 2022
b5ce4ea
Update react-redux 7.2.6 > 7.2.8
Gnito May 18, 2022
5df20e2
Remove @formatjs/intl-relativetimeformat since browser support has im…
Gnito May 18, 2022
4d7c28e
Remove @formatjs/intl-pluralrules since browser support has improved
Gnito May 18, 2022
d5ba34c
Update changelog
Gnito May 18, 2022
29520a9
Merge pull request #1514 from sharetribe/update-libs
Gnito May 18, 2022
9273c09
Rename currentCanonicalUrl to reflect the content: currentCanonicalPath
Gnito Apr 21, 2022
b6ec6ff
Analytics handlers: include previous path when calling trackPageView
Gnito Apr 21, 2022
6bcfbef
Google Analytics: use GA4 instead of deprecated Universal Analytics
Gnito Apr 21, 2022
af97b27
Update .env-template instructions
Gnito Apr 22, 2022
512ddc9
Update CSP
Gnito May 6, 2022
df9cfa8
Update changelog
Gnito Apr 22, 2022
9b556fa
Merge pull request #1508 from sharetribe/remove-ga-add-gtag-script
Gnito May 19, 2022
c819bd8
New release
Gnito May 19, 2022
7000098
Merge pull request #1515 from sharetribe/v8.6.0
Gnito May 19, 2022
0a9a118
Merge commit '70000986500320f18ceffccfda37d94166a36076' into update-v…
Gnito May 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
jobs:
format:
docker:
- image: circleci/node:12.19
- image: circleci/node:12.20
steps:
- checkout
- restore_cache:
Expand All @@ -25,7 +25,7 @@ jobs:
command: yarn run format-ci
test:
docker:
- image: circleci/node:12.19
- image: circleci/node:12.20
steps:
- checkout
- restore_cache:
Expand All @@ -48,7 +48,7 @@ jobs:
command: yarn run test-ci
build:
docker:
- image: circleci/node:12.19
- image: circleci/node:12.20
steps:
- checkout
- restore_cache:
Expand All @@ -71,7 +71,7 @@ jobs:
command: yarn run build
audit:
docker:
- image: circleci/node:12.19
- image: circleci/node:12.20
steps:
- checkout
- restore_cache:
Expand Down
4 changes: 4 additions & 0 deletions .env-template
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ REACT_APP_CSP=report
# REACT_APP_SENTRY_DSN=change-me
# BASIC_AUTH_USERNAME=sharetribe
# BASIC_AUTH_PASSWORD=secret

# This is GA4 id, which should start with 'G-' prefix.
# You should also turn "Enhanced measurements" off from GA.
# https://support.google.com/analytics/answer/9216061
# REACT_APP_GOOGLE_ANALYTICS_ID=change-me
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ way to update this template, but currently, we follow a pattern:

## Upcoming version 2022-XX-XX

## [v9.3.0] 2022-05-19

### Updates from upstream (FTW-daily v8.6.0)

- [change] Google Analytics: remove Universal Analytics and start supporting GA4.

NOTE: you need to update the Google Analytics id to GA4's id (starting with 'G-' prefix).

[#1508](https://github.com/sharetribe/ftw-daily/pull/1508)

- [change] Update some outdated dependencies.
[#1514](https://github.com/sharetribe/ftw-daily/pull/1514)

[v9.3.0]: https://github.com/sharetribe/ftw-product/compare/v9.2.0...v9.3.0

## [v9.2.0] 2022-05-16

- Add support for hosted translations. (PR made in upstream repo: FTW-daily)
Expand Down
50 changes: 24 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,62 +1,60 @@
{
"name": "app",
"version": "9.2.0",
"version": "9.3.0",
"private": true,
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.16.3",
"@formatjs/intl-relativetimeformat": "^9.3.2",
"@babel/runtime": "^7.17.9",
"@loadable/component": "^5.14.1",
"@loadable/server": "^5.14.2",
"@mapbox/polyline": "^1.1.1",
"@sentry/browser": "^6.15.0",
"@sentry/node": "^6.15.0",
"array-includes": "^3.1.4",
"array.prototype.find": "^2.1.2",
"@sentry/browser": "^6.19.7",
"@sentry/node": "^6.19.7",
"array-includes": "^3.1.5",
"array.prototype.find": "^2.2.0",
"autosize": "^5.0.1",
"basic-auth": "^2.0.1",
"body-parser": "^1.18.3",
"body-parser": "^1.20.0",
"classnames": "^2.3.1",
"compression": "^1.7.4",
"cookie-parser": "^1.4.6",
"core-js": "^3.19.2",
"core-js": "^3.22.5",
"cors": "^2.8.5",
"decimal.js": "^10.3.1",
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0",
"express": "^4.16.4",
"express": "^4.18.1",
"express-enforces-ssl": "^1.1.0",
"express-sitemap": "^1.8.0",
"final-form": "^4.20.4",
"final-form": "^4.20.7",
"final-form-arrays": "^3.0.2",
"full-icu": "^1.4.0",
"helmet": "^4.6.0",
"intl-pluralrules": "^1.3.1",
"jose": "3.11.4",
"jose": "4.8.1",
"lodash": "^4.17.21",
"mapbox-gl-multitouch": "^1.0.3",
"moment": "^2.29.1",
"moment": "^2.29.3",
"moment-timezone": "^0.5.34",
"object.entries": "^1.1.5",
"object.values": "^1.1.5",
"passport": "^0.5.0",
"passport": "^0.5.3",
"passport-facebook": "^3.0.0",
"passport-google-oauth": "^2.0.0",
"path-to-regexp": "^6.2.0",
"prop-types": "^15.7.2",
"query-string": "^7.0.1",
"path-to-regexp": "^6.2.1",
"prop-types": "^15.8.1",
"query-string": "^7.1.1",
"raf": "^3.4.0",
"react": "^16.13.1",
"react-dates": "^21.8.0",
"react-dom": "^16.13.1",
"react-final-form": "^6.5.7",
"react-final-form": "^6.5.9",
"react-final-form-arrays": "^3.1.3",
"react-helmet-async": "^1.1.2",
"react-helmet-async": "^1.3.0",
"react-image-gallery": "^1.0.9",
"react-intl": "^5.22.0",
"react-intl": "^5.25.1",
"react-moment-proptypes": "^1.8.1",
"react-redux": "^7.2.6",
"react-router-dom": "^5.2.0",
"react-redux": "^7.2.8",
"react-router-dom": "^5.3.2",
"react-with-direction": "^1.4.0",
"redux": "^4.1.2",
"redux-thunk": "^2.4.1",
Expand All @@ -70,12 +68,12 @@
"devDependencies": {
"bfj": "^7.0.2",
"chalk": "^v4.1.2",
"concurrently": "^6.4.0",
"concurrently": "^7.2.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"enzyme-to-json": "^3.6.2",
"inquirer": "^8.2.0",
"nodemon": "^2.0.15",
"inquirer": "^8.2.4",
"nodemon": "^2.0.16",
"prettier": "^1.18.2"
},
"resolutions": {
Expand Down
7 changes: 3 additions & 4 deletions server/api-util/idToken.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const crypto = require('crypto');
const { default: fromKeyLike } = require('jose/jwk/from_key_like');
const { default: SignJWT } = require('jose/jwt/sign');
const jose = require('jose');

const radix = 10;
const PORT = parseInt(process.env.REACT_APP_DEV_API_SERVER_PORT, radix);
Expand Down Expand Up @@ -50,7 +49,7 @@ exports.createIdToken = (idpClientId, user, options) => {

const { userId, firstName, lastName, email, emailVerified } = user;

const jwt = new SignJWT({
const jwt = new jose.SignJWT({
given_name: firstName,
family_name: lastName,
email: email,
Expand Down Expand Up @@ -89,7 +88,7 @@ exports.openIdConfiguration = (req, res) => {
*/
exports.jwksUri = keys => (req, res) => {
const jwkKeys = keys.map(key => {
return fromKeyLike(crypto.createPublicKey(key.rsaPublicKey)).then(res => {
return jose.exportJWK(crypto.createPublicKey(key.rsaPublicKey)).then(res => {
return { alg: key.alg, kid: key.keyId, ...res };
});
});
Expand Down
3 changes: 3 additions & 0 deletions server/csp.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const defaultDirectives = {
'events.mapbox.com',

// Google Analytics
'​www.​googletagm­anager.​com',
'www.google-analytics.com',
'stats.g.doubleclick.net',

Expand All @@ -58,6 +59,7 @@ const defaultDirectives = {
'*.ggpht.com',

// Google Analytics
'www.googletagmanager.com',
'www.google.com',
'www.google-analytics.com',
'stats.g.doubleclick.net',
Expand All @@ -71,6 +73,7 @@ const defaultDirectives = {
data,
'maps.googleapis.com',
'api.mapbox.com',
'​www.​googletagm­anager.​com',
'*.google-analytics.com',
'js.stripe.com',
],
Expand Down
35 changes: 23 additions & 12 deletions server/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,31 @@ exports.render = function(requestUrl, context, data, renderApp, webExtractor) {

// We want to precisely control where the analytics script is
// injected in the HTML file so we can catch all events as early as
// possible. This is why we inject the GA script separately from
// react-helmet. This script also ensures that all the GA scripts
// possible. This script also ensures that all the GA scripts
// are added only when the proper env var is present.
// NOTE: when dealing with cookie consents, it might make more sense to
// include this script through react-helmet.
//
// See: https://developers.google.com/analytics/devguides/collection/analyticsjs/#alternative_async_tracking_snippet
const googleAnalyticsScript = process.env.REACT_APP_GOOGLE_ANALYTICS_ID
? `
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', '${process.env.REACT_APP_GOOGLE_ANALYTICS_ID}', 'auto');
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
`
: '';
// See: https://developers.google.com/analytics/devguides/collection/gtagjs
const googleAnalyticsId = process.env.REACT_APP_GOOGLE_ANALYTICS_ID;
// Add Google Analytics script if correct id exists (it should start with 'G-' prefix)
const hasGoogleAnalyticsv4Id = googleAnalyticsId.indexOf('G-') === 0;

// Google Analytics: gtag.js
// NOTE: FTW is a single-page application (SPA).
// gtag.js sends initial page_view event after page load.
// but we need to handle subsequent events for in-app navigation.
const gtagScripts = `
<script async src="https://www.googletagmanager.com/gtag/js?id=${googleAnalyticsId}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', '${googleAnalyticsId}');
</script>
`;
const googleAnalyticsScript = hasGoogleAnalyticsv4Id ? gtagScripts : '';

return template({
htmlAttributes: head.htmlAttributes.toString(),
Expand Down
9 changes: 5 additions & 4 deletions src/analytics/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { LOCATION_CHANGED } from '../ducks/Routing.duck';
// Create a Redux middleware from the given analytics handlers. Each
// handler should have the following methods:
//
// - trackPageView(url): called when the URL is changed
export const createMiddleware = handlers => () => next => action => {
// - trackPageView(canonicalPath, previousPath): called when the URL is changed
export const createMiddleware = handlers => store => next => action => {
const { type, payload } = action;

if (type === LOCATION_CHANGED) {
const { canonicalUrl } = payload;
const previousPath = store?.getState()?.Routing?.currentCanonicalPath;
const { canonicalPath } = payload;
handlers.forEach(handler => {
handler.trackPageView(canonicalUrl);
handler.trackPageView(canonicalPath, previousPath);
});
}

Expand Down
30 changes: 22 additions & 8 deletions src/analytics/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,30 @@ export class LoggingAnalyticsHandler {
}
}

// Google Analytics 4 (GA4) using gtag.js script, which is included in server/rendered.js
// Note: the script is only available locally when running "yarn run dev-server"
export class GoogleAnalyticsHandler {
constructor(ga) {
if (typeof ga !== 'function') {
throw new Error('Variable `ga` missing for Google Analytics');
constructor(gtag) {
if (typeof gtag !== 'function') {
throw new Error('Variable `gtag` missing for Google Analytics');
}
this.ga = ga;
this.gtag = gtag;
}
trackPageView(url) {
// https://developers.google.com/analytics/devguides/collection/analyticsjs/single-page-applications#tracking_virtual_pageviews
this.ga('set', 'page', url);
this.ga('send', 'pageview');
trackPageView(canonicalPath, previousPath) {
// GA4 property. Manually send page_view events
// https://developers.google.com/analytics/devguides/collection/gtagjs/single-page-applications
// Note 1: You should turn "Enhanced measurement" off.
// It attaches own listeners to elements and that breaks in-app navigation.
// Note 2: If previousPath is null (just after page load), gtag script sends page_view event automatically.
// Only in-app navigation needs to be sent manually from SPA.
// Note 3: Timeout is needed because gtag script picks up <title>,
// and location change event happens before initial rendering.
if (previousPath) {
window.setTimeout(() => {
this.gtag('event', 'page_view', {
page_path: canonicalPath,
});
}, 300);
}
}
}
3 changes: 2 additions & 1 deletion src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import defaultMessages from './translations/en.json';
// 1) Change the language in the config.js file!
// 2) Import correct locale rules for Moment library
// 3) Use the `messagesInLocale` import to add the correct translation file.
// 4) To support older browsers we need add the correct locale for intl-relativetimeformat to `util/polyfills.js`
// 4) (optionally) To support older browsers you need add the intl-relativetimeformat npm packages
// and take it into use in `util/polyfills.js`

// Note that there is also translations in './translations/countryCodes.js' file
// This file contains ISO 3166-1 alpha-2 country codes, country names and their translations in our default languages
Expand Down
8 changes: 4 additions & 4 deletions src/ducks/Routing.duck.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const LOCATION_CHANGED = 'app/Routing/LOCATION_CHANGED';

const initialState = {
currentLocation: null,
currentCanonicalUrl: null,
currentCanonicalPath: null,
};

export default function routingReducer(state = initialState, action = {}) {
Expand All @@ -16,7 +16,7 @@ export default function routingReducer(state = initialState, action = {}) {
return {
...state,
currentLocation: payload.location,
currentCanonicalUrl: payload.canonicalUrl,
currentCanonicalPath: payload.canonicalPath,
};

default:
Expand All @@ -26,7 +26,7 @@ export default function routingReducer(state = initialState, action = {}) {

// ================ Action creators ================ //

export const locationChanged = (location, canonicalUrl) => ({
export const locationChanged = (location, canonicalPath) => ({
type: LOCATION_CHANGED,
payload: { location, canonicalUrl },
payload: { location, canonicalPath },
});
13 changes: 9 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,19 @@ const setupAnalyticsHandlers = () => {
handlers.push(new LoggingAnalyticsHandler());
}

// Add Google Analytics handler if tracker ID is found
// Add Google Analytics 4 (GA4) handler if tracker ID is found
if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) {
if (window?.ga) {
handlers.push(new GoogleAnalyticsHandler(window.ga));
if (window?.gtag) {
handlers.push(new GoogleAnalyticsHandler(window.gtag));
} else {
// Some adblockers (e.g. Ghostery) might block the Google Analytics integration.
console.warn(
'Google Analytics (window.ga) is not available. It might be that your adblocker is blocking it.'
'Google Analytics (window.gtag) is not available. It might be that your adblocker is blocking it.'
);
}
if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID.indexOf('G-') !== 0) {
console.warn(
'Google Analytics 4 (GA4) should have measurement id that starts with "G-" prefix'
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/routing/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ const setPageScrollPosition = location => {

const handleLocationChanged = (dispatch, location) => {
setPageScrollPosition(location);
const url = canonicalRoutePath(routeConfiguration(), location);
dispatch(locationChanged(location, url));
const path = canonicalRoutePath(routeConfiguration(), location);
dispatch(locationChanged(location, path));
};

/**
Expand Down
Loading