Skip to content

Commit c1be24c

Browse files
Cookie consent integration (#1124)
This integrates the new microbit.org-wide cookie consent approach. Mostly this is delegated to the deployment code, but the line between the two changes. New action added to the help menu so cookie settings can be revisited. The welcome dialog is delayed until after a cookie decision is made to avoid a clash of modals.
1 parent 27ef5fb commit c1be24c

29 files changed

+190
-64
lines changed

.github/workflows/build.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
PRODUCTION_CLOUDFRONT_DISTRIBUTION_ID: E2ELTBTA2OFPY2
2323
STAGING_CLOUDFRONT_DISTRIBUTION_ID: E2ELTBTA2OFPY2
2424
REVIEW_CLOUDFRONT_DISTRIBUTION_ID: E3267W09ZJHQG9
25+
REACT_APP_FOUNDATION_BUILD: ${{ github.repository_owner == 'microbit-foundation' }}
2526

2627
steps:
2728
# Note: This workflow disables deployment steps and micro:bit branding installation on forks.
@@ -35,7 +36,7 @@ jobs:
3536
- run: npm ci
3637
env:
3738
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38-
- run: npm install --no-save @microbit-foundation/python-editor-v3-microbit@0.1.0-dev.198 @microbit-foundation/[email protected] @microbit-foundation/[email protected] @microbit-foundation/circleci-npm-package-versioner@1
39+
- run: npm install --no-save @microbit-foundation/python-editor-v3-microbit@0.2.0-dev.18 @microbit-foundation/[email protected] @microbit-foundation/[email protected] @microbit-foundation/circleci-npm-package-versioner@1
3940
if: github.repository_owner == 'microbit-foundation'
4041
env:
4142
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

lang/ui.ca.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "Alguna cosa ha anat malament. Baixa el teu fitxer hexadecimal per mantenir-lo segur i, a continuació, actualitza la pàgina per tornar-la a carregar.",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "Copiat",
200204
"description": "Text shown after copy to clipboard"

lang/ui.en.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "Something went wrong. Download your hex file for safe keeping, then refresh the page to reload.",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "Copied",
200204
"description": "Text shown after copy to clipboard"

lang/ui.es-es.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "Algo salió mal. Por seguridad, descarga tu archivo HEX y actualiza la página para recargar.",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "Copiado",
200204
"description": "Text shown after copy to clipboard"

lang/ui.fr.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "Une erreur est survenue. Téléchargez votre fichier hex pour ne pas le perdre, puis actualisez la page.",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "Copié",
200204
"description": "Text shown after copy to clipboard"

lang/ui.ja.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "問題が発生しました。hex ファイルをダウンロードして、ページをリロードしてください。",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "コピーしました",
200204
"description": "Text shown after copy to clipboard"

lang/ui.ko.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "오류가 발생했습니다. hex 파일을 다운로드해 작업물을 보호하고 새로 고침으로 페이지를 다시 불러오세요.",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "복사됨",
200204
"description": "Text shown after copy to clipboard"

lang/ui.nl.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "Er is iets fout gegaan. Download je hexadecimale bestand voor een veilige bewaring, ververs daarna de pagina om te herladen.",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "Gekopieerd",
200204
"description": "Text shown after copy to clipboard"

lang/ui.zh-cn.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "出错了。下载您的 hex 文件以便安全保存,然后刷新页面来重新加载。",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "已复制",
200204
"description": "Text shown after copy to clipboard"

lang/ui.zh-tw.json

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"defaultMessage": "發生錯誤。下載您的 HEX 檔案以便安全儲存,然後重新整理頁面來重新載入。",
196196
"description": "Text displayed when content fails to load"
197197
},
198+
"cookies-action": {
199+
"defaultMessage": "Cookies",
200+
"description": "Action to show dialog to choose website cookie preferences"
201+
},
198202
"copied": {
199203
"defaultMessage": "複製的",
200204
"description": "Text shown after copy to clipboard"

package-lock.json

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"mobile-drag-drop": "^2.3.0-rc.2",
4646
"react": "^17.0.2",
4747
"react-dom": "^17.0.2",
48-
"react-icons": "^4.2.0",
48+
"react-icons": "^4.8.0",
4949
"react-intl": "^5.20.10",
5050
"vscode-jsonrpc": "^6.0.0",
5151
"vscode-languageserver-protocol": "^3.16.0",

public/index.html

+5-15
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,15 @@
2020
name="twitter:description"
2121
content="A Python Editor for the BBC micro:bit, built by the Micro:bit Educational Foundation and the global Python Community."
2222
/>
23-
<% if (process.env.REACT_APP_GA_MEASUREMENT_ID &&
24-
(process.env.REACT_APP_STAGE === 'PRODUCTION' || process.env.REACT_APP_STAGE
25-
=== "STAGING")) { %>
26-
<script
27-
async
28-
src="https://www.googletagmanager.com/gtag/js?id=%REACT_APP_GA_MEASUREMENT_ID%"
29-
></script>
23+
<% if (process.env.REACT_APP_FOUNDATION_BUILD === 'true') { %>
24+
<script src="https://shared-assets.microbit.org/common/v1/common.js" async></script>
25+
<link rel="stylesheet" href="https://shared-assets.microbit.org/common/v1/main.css"></link>
3026
<script>
27+
// GA config itself is via the common assets config depending on consent.
3128
window.dataLayer = window.dataLayer || [];
32-
window.gaMeasurementId = "%REACT_APP_GA_MEASUREMENT_ID%";
33-
window.gtag = function () {
29+
window.gtag = window.gtag || function() {
3430
window.dataLayer.push(arguments);
3531
};
36-
gtag("js", new Date());
37-
var options = {
38-
anonymize_ip: true,
39-
cookie_prefix: "%REACT_APP_GA_COOKIE_PREFIX%",
40-
};
41-
gtag("config", window.gaMeasurementId, options);
4232
</script>
4333
<% } %>
4434
</head>

src/App.tsx

+8-5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const App = () => {
6262
});
6363

6464
const deployment = useDeployment();
65+
const { ConsentProvider } = deployment.compliance;
6566
return (
6667
<>
6768
<VisualViewPortCSSVariables />
@@ -79,11 +80,13 @@ const App = () => {
7980
<SelectionProvider>
8081
<DialogProvider>
8182
<RouterProvider>
82-
<ProjectDropTarget>
83-
<ActiveEditorProvider>
84-
<Workbench />
85-
</ActiveEditorProvider>
86-
</ProjectDropTarget>
83+
<ConsentProvider>
84+
<ProjectDropTarget>
85+
<ActiveEditorProvider>
86+
<Workbench />
87+
</ActiveEditorProvider>
88+
</ProjectDropTarget>
89+
</ConsentProvider>
8790
</RouterProvider>
8891
</DialogProvider>
8992
</SelectionProvider>

src/deployment/default/index.tsx

+19-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,31 @@
33
*
44
* SPDX-License-Identifier: MIT
55
*/
6-
import { DeploymentConfig } from "..";
6+
import { createContext } from "react";
7+
import { CookieConsent, DeploymentConfig } from "..";
78
import { NullLogging } from "./logging";
89
import theme from "./theme";
910

11+
const stubConsentValue: CookieConsent = {
12+
analytics: false,
13+
functional: true,
14+
};
15+
const stubConsentContext = createContext<CookieConsent | undefined>(
16+
stubConsentValue
17+
);
18+
1019
const defaultDeployment: DeploymentConfig = {
1120
chakraTheme: theme,
1221
logging: new NullLogging(),
22+
compliance: {
23+
ConsentProvider: ({ children }) => (
24+
<stubConsentContext.Provider value={stubConsentValue}>
25+
{children}
26+
</stubConsentContext.Provider>
27+
),
28+
consentContext: stubConsentContext,
29+
manageCookies: undefined,
30+
},
1331
};
1432

1533
export default defaultDeployment;

src/deployment/index.ts

+26-9
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,36 @@
33
*
44
* SPDX-License-Identifier: MIT
55
*/
6-
import { ReactNode } from "react";
7-
import { IconType } from "react-icons/lib";
6+
import { ReactNode, useContext } from "react";
87
import { Logging } from "../logging/logging";
98

109
// This is configured via a webpack alias, defaulting to ./default
1110
import { default as d } from "theme-package";
1211
export const deployment: DeploymentConfig = d;
1312

13+
export interface CookieConsent {
14+
analytics: boolean;
15+
functional: boolean;
16+
}
17+
1418
export interface DeploymentConfig {
1519
squareLogo?: ReactNode;
1620
horizontalLogo?: ReactNode;
17-
Compliance?: ({
18-
zIndex,
19-
externalLinkIcon,
20-
}: {
21-
zIndex: number;
22-
externalLinkIcon: IconType;
23-
}) => JSX.Element;
21+
compliance: {
22+
/**
23+
* A provider that will be used to wrap the app UI.
24+
*/
25+
ConsentProvider: (props: { children: ReactNode }) => JSX.Element;
26+
/**
27+
* Context that will be used to read the current consent value.
28+
* The provider is not used directly.
29+
*/
30+
consentContext: React.Context<CookieConsent | undefined>;
31+
/**
32+
* Optional hook for the user to revisit cookie settings.
33+
*/
34+
manageCookies: (() => void) | undefined;
35+
};
2436

2537
chakraTheme: any;
2638

@@ -35,3 +47,8 @@ export interface DeploymentConfig {
3547
export const useDeployment = (): DeploymentConfig => {
3648
return deployment;
3749
};
50+
51+
export const useCookieConsent = (): CookieConsent | undefined => {
52+
const { compliance } = useDeployment();
53+
return useContext(compliance.consentContext);
54+
};

src/e2e/app.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,16 @@ export class App {
126126
value: "1",
127127
url: this.url,
128128
});
129-
// Don't show compliance notice.
129+
// Don't show compliance notice for Foundation builds
130130
await page.setCookie({
131131
name: "MBCC",
132-
value: "1",
132+
value: encodeURIComponent(
133+
JSON.stringify({
134+
version: 1,
135+
analytics: false,
136+
functional: true,
137+
})
138+
),
133139
url: this.url,
134140
});
135141

src/messages/ui.ca.json

+6
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,12 @@
411411
"value": "Alguna cosa ha anat malament. Baixa el teu fitxer hexadecimal per mantenir-lo segur i, a continuació, actualitza la pàgina per tornar-la a carregar."
412412
}
413413
],
414+
"cookies-action": [
415+
{
416+
"type": 0,
417+
"value": "Cookies"
418+
}
419+
],
414420
"copied": [
415421
{
416422
"type": 0,

src/messages/ui.en.json

+6
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,12 @@
407407
"value": "Something went wrong. Download your hex file for safe keeping, then refresh the page to reload."
408408
}
409409
],
410+
"cookies-action": [
411+
{
412+
"type": 0,
413+
"value": "Cookies"
414+
}
415+
],
410416
"copied": [
411417
{
412418
"type": 0,

src/messages/ui.es-es.json

+6
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,12 @@
411411
"value": "Algo salió mal. Por seguridad, descarga tu archivo HEX y actualiza la página para recargar."
412412
}
413413
],
414+
"cookies-action": [
415+
{
416+
"type": 0,
417+
"value": "Cookies"
418+
}
419+
],
414420
"copied": [
415421
{
416422
"type": 0,

src/messages/ui.fr.json

+6
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,12 @@
407407
"value": "Une erreur est survenue. Téléchargez votre fichier hex pour ne pas le perdre, puis actualisez la page."
408408
}
409409
],
410+
"cookies-action": [
411+
{
412+
"type": 0,
413+
"value": "Cookies"
414+
}
415+
],
410416
"copied": [
411417
{
412418
"type": 0,

src/messages/ui.ja.json

+6
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,12 @@
431431
"value": "問題が発生しました。hex ファイルをダウンロードして、ページをリロードしてください。"
432432
}
433433
],
434+
"cookies-action": [
435+
{
436+
"type": 0,
437+
"value": "Cookies"
438+
}
439+
],
434440
"copied": [
435441
{
436442
"type": 0,

0 commit comments

Comments
 (0)