Add application insights and cookie banner to Storybook (#155)
This commit is contained in:
Родитель
430c147a54
Коммит
a874dcb3b6
|
@ -75,6 +75,7 @@ jobs:
|
|||
working-directory: ./packages/storybook
|
||||
env:
|
||||
GH_TOKEN: ${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}
|
||||
TELEMETRY_INSTRUMENTATION_KEY: ${{ secrets.TELEMETRY_INSTRUMENTATION_KEY }}
|
||||
|
||||
# Create a GitHub issue if the CI failed when running on the `main` branch
|
||||
- name: Create issue if main branch CI failed
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -29,7 +29,8 @@ module.exports = {
|
|||
// Note: This triggers babel to retranspile all package dependency files during webpack's compilation step.
|
||||
config.resolve.alias = {
|
||||
...(config.resolve.alias || {}),
|
||||
"@azure/communication-ui": path.resolve(__dirname, "../../communication-ui/src")
|
||||
"@azure/communication-ui": path.resolve(__dirname, "../../communication-ui/src"),
|
||||
"@azure/acs-chat-selector": path.resolve(__dirname, "../../acs-chat-selector/src")
|
||||
}
|
||||
|
||||
return config;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<script src="https://wcpstatic.microsoft.com/mscc/lib/v2/wcp-consent.js"></script>
|
||||
|
||||
<script>
|
||||
window.addEventListener('load', () => {
|
||||
const cookieBannerId = 'cookie-banner';
|
||||
const cookieBannerContainer = document.createElement('div');
|
||||
cookieBannerContainer.id = cookieBannerId;
|
||||
document.body.insertBefore(cookieBannerContainer, document.body.firstChild);
|
||||
|
||||
function onConsentChanged(categoryPreferences) {
|
||||
window.cookieConsentChanged && window.cookieConsentChanged();
|
||||
}
|
||||
|
||||
function initCallback(err, _siteConsent) {
|
||||
if (!err) {
|
||||
siteConsent = _siteConsent; // siteConsent is used to get the current consent
|
||||
window.cookieConsentChanged && window.cookieConsentChanged(); // call callback now cookie library has finished initializing
|
||||
} else {
|
||||
console.log(`Error initializing WcpConsent: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
window.WcpConsent && WcpConsent.init('en-US', cookieBannerId, initCallback, onConsentChanged, WcpConsent.themes.light);
|
||||
});
|
||||
</script>
|
|
@ -1,5 +1,8 @@
|
|||
import { create } from '@storybook/theming';
|
||||
import { addons } from '@storybook/addons';
|
||||
import { initTelemetry } from './telemetry';
|
||||
|
||||
initTelemetry();
|
||||
|
||||
addons.setConfig({
|
||||
theme: create({
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import { analyticsCookieConsentObtained } from "./telemetry";
|
||||
|
||||
describe('storybook telemetry util tests', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// reset cookie consent window variables
|
||||
(window as any).siteConsent = undefined;
|
||||
})
|
||||
|
||||
describe ('test analyticsCookieConsentObtained', () => {
|
||||
|
||||
test('analyticsCookieConsentObtained returns false if telemetry library is not initialized', () => {
|
||||
// set cookie consent library to uninitialized
|
||||
(window as any).siteConsent = undefined;
|
||||
|
||||
const result = analyticsCookieConsentObtained();
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
test('analyticsCookieConsentObtained returns false if telemetry library is initialized but consent has not been obtained', () => {
|
||||
// set cookie consent library to uninitialized
|
||||
(window as any).siteConsent = {
|
||||
isConsentRequired: true,
|
||||
getConsent: () => ({
|
||||
Required: true,
|
||||
Analytics: false
|
||||
})
|
||||
};
|
||||
|
||||
const result = analyticsCookieConsentObtained();
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
test('analyticsCookieConsentObtained returns true if telemetry library is initialized and consent has been obtained', () => {
|
||||
// set cookie consent library to uninitialized
|
||||
(window as any).siteConsent = {
|
||||
isConsentRequired: true,
|
||||
getConsent: () => ({
|
||||
Required: true,
|
||||
Analytics: true
|
||||
})
|
||||
};
|
||||
|
||||
const result = analyticsCookieConsentObtained();
|
||||
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
test('analyticsCookieConsentObtained returns true if telemetry library is initialized but consent is not required', () => {
|
||||
// set cookie consent library to uninitialized
|
||||
(window as any).siteConsent = {
|
||||
isConsentRequired: false,
|
||||
getConsent: () => ({
|
||||
Required: false,
|
||||
Analytics: false
|
||||
})
|
||||
};
|
||||
|
||||
const result = analyticsCookieConsentObtained();
|
||||
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
})
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
import { ApplicationInsights } from '@microsoft/applicationinsights-web'
|
||||
import { ReactPlugin } from '@microsoft/applicationinsights-react-js';
|
||||
import { createBrowserHistory } from "history";
|
||||
|
||||
/**
|
||||
* Check if we have the necessary cookie consent to allow the app insights library to make use of cookies
|
||||
*/
|
||||
export const analyticsCookieConsentObtained = (): boolean => {
|
||||
return !!(window as any).siteConsent && // has telemetry library been initialized
|
||||
(!(window as any).siteConsent.isConsentRequired || // check if we need collect consent in this region
|
||||
(window as any).siteConsent.getConsent().Analytics); // check if we have consent to collect analytics telemetry
|
||||
}
|
||||
|
||||
/**
|
||||
* Start telemetry collection and watch for cookie consent changes.
|
||||
*/
|
||||
export const initTelemetry = () => {
|
||||
const appInsightsInstance = startTelemetry(analyticsCookieConsentObtained());
|
||||
|
||||
if (appInsightsInstance) {
|
||||
createCookieChangedCallback(appInsightsInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the window.cookieConsentChanged that is called when the cookie banner's onConsentChanged is called.
|
||||
* @param applicationInsightsInstance application instance that enables or disables appInsight's cookie manager
|
||||
*/
|
||||
const createCookieChangedCallback = (applicationInsightsInstance: ApplicationInsights) => {
|
||||
(window as any).cookieConsentChanged = () => {
|
||||
const analyticsCookieConsent = analyticsCookieConsentObtained();
|
||||
applicationInsightsInstance.getCookieMgr().setEnabled(analyticsCookieConsent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start app insights tracking telemetry
|
||||
* @param cookieConsent do we have consent to collect cookies for analytics purposes
|
||||
* @returns the created instance of the application insights library
|
||||
*/
|
||||
const startTelemetry = (cookieConsent: boolean): ApplicationInsights | undefined => {
|
||||
const instrumentationKey = process.env.TELEMETRY_INSTRUMENTATION_KEY;
|
||||
if (!instrumentationKey) {
|
||||
console.warn('No telemetry instrumentationKey provided. Telemetry collection is disabled.')
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize telemetry react plugin
|
||||
const browserHistory = createBrowserHistory({ window });
|
||||
var reactPlugin = new ReactPlugin();
|
||||
|
||||
|
||||
// Initialize and start collecting telemetry
|
||||
const appInsights = new ApplicationInsights({
|
||||
config: {
|
||||
disableCookiesUsage: !cookieConsent,
|
||||
instrumentationKey,
|
||||
enableAutoRouteTracking: true,
|
||||
extensions: [reactPlugin],
|
||||
extensionConfig: {
|
||||
[reactPlugin.identifier]: { history: browserHistory }
|
||||
}
|
||||
}
|
||||
});
|
||||
appInsights.loadAppInsights();
|
||||
|
||||
return appInsights;
|
||||
}
|
|
@ -105,10 +105,10 @@ module.exports = {
|
|||
// restoreMocks: false,
|
||||
|
||||
// The root directory that Jest should scan for tests and modules within
|
||||
rootDir: './stories',
|
||||
rootDir: '.',
|
||||
|
||||
// A list of paths to directories that Jest should use to search for files in
|
||||
// roots: ['stories'],
|
||||
roots: ['stories', '.storybook'],
|
||||
|
||||
// Allows you to use a custom runner instead of Jest's default test runner
|
||||
// runner: "jest-runner",
|
||||
|
@ -161,7 +161,7 @@ module.exports = {
|
|||
// A map from regular expressions to paths to transformers
|
||||
transform: {
|
||||
'^.+\\.(ts)x?$': 'ts-jest',
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '<rootDir>/../jest/fileTransform.js'
|
||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '<rootDir>/jest/fileTransform.js'
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
|
|
|
@ -30,11 +30,14 @@
|
|||
"@fluentui/react-icons-northstar": "^0.51.2",
|
||||
"@fluentui/react-northstar": "^0.51.2",
|
||||
"@fluentui/react-theme-provider": "^0.18.0",
|
||||
"classnames": "^2.2.6",
|
||||
"react-aria-live": "^2.0.5",
|
||||
"react-linkify": "^1.0.0-alpha",
|
||||
"@microsoft/applicationinsights-react-js": "~3.0.5",
|
||||
"@microsoft/applicationinsights-web": "~2.6.1",
|
||||
"@uifabric/react-hooks": "~7.13.11",
|
||||
"copy-to-clipboard": "~3.3.1"
|
||||
"classnames": "^2.2.6",
|
||||
"copy-to-clipboard": "~3.3.1",
|
||||
"history": "~5.0.0",
|
||||
"react-aria-live": "^2.0.5",
|
||||
"react-linkify": "^1.0.0-alpha"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1",
|
||||
|
@ -46,16 +49,16 @@
|
|||
"@mdx-js/react": "^1.6.22",
|
||||
"@microsoft/api-documenter": "~7.12.11",
|
||||
"@microsoft/api-extractor": "~7.13.2",
|
||||
"@storybook/addon-actions": "^6.1.1",
|
||||
"@storybook/addon-docs": "^6.1.18",
|
||||
"@storybook/addon-essentials": "^6.1.1",
|
||||
"@storybook/addon-knobs": "^6.1.9",
|
||||
"@storybook/addon-links": "^6.1.1",
|
||||
"@storybook/addon-storyshots": "^6.1.6",
|
||||
"@storybook/node-logger": "^6.1.1",
|
||||
"@storybook/react": "^6.1.1",
|
||||
"@storybook/storybook-deployer": "^2.8.7",
|
||||
"@storybook/theming": "^6.1.10",
|
||||
"@storybook/addon-actions": "~6.1.1",
|
||||
"@storybook/addon-docs": "~6.1.18",
|
||||
"@storybook/addon-essentials": "~6.1.1",
|
||||
"@storybook/addon-knobs": "~6.1.9",
|
||||
"@storybook/addon-links": "~6.1.1",
|
||||
"@storybook/addon-storyshots": "~6.1.6",
|
||||
"@storybook/node-logger": "~6.1.1",
|
||||
"@storybook/react": "~6.1.1",
|
||||
"@storybook/storybook-deployer": "~2.8.7",
|
||||
"@storybook/theming": "~6.1.10",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react-hooks": "^3.4.2",
|
||||
"@types/classnames": "^2.2.11",
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import { Meta } from '@storybook/react/types-6-0';
|
||||
import { PrimaryButton } from '@fluentui/react';
|
||||
|
||||
function openManageCookiesModal(): void {
|
||||
(window as any).parent.siteConsent?.manageConsent();
|
||||
}
|
||||
|
||||
export const ManageCookies: () => JSX.Element = () => {
|
||||
const manageCookiesRequired = (window as any).parent.siteConsent?.isConsentRequired;
|
||||
const buttonText = manageCookiesRequired ? 'Manage Cookies' : 'Manage Cookies unavailable';
|
||||
return <PrimaryButton text={buttonText} onClick={openManageCookiesModal} disabled={!manageCookiesRequired} />;
|
||||
};
|
||||
|
||||
export default {
|
||||
title: `Settings/Manage Cookies`
|
||||
} as Meta;
|
|
@ -1000,6 +1000,59 @@ exports[`storybook snapshot tests Storyshots Examples/Themes Teams Theme Compone
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`storybook snapshot tests Storyshots Settings/Manage Cookies Manage Cookies 1`] = `
|
||||
<div
|
||||
className="css-75 root-0 body-1"
|
||||
>
|
||||
<div
|
||||
className="css-75"
|
||||
data-uses-unhanded-props={true}
|
||||
dir="ltr"
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "flex",
|
||||
"height": "100vh",
|
||||
"justifyContent": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
aria-disabled={true}
|
||||
className="ms-Button ms-Button--primary is-disabled root-2"
|
||||
data-is-focusable={false}
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyPress={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="ms-Button-flexContainer flexContainer-3"
|
||||
data-automationid="splitbuttonprimary"
|
||||
>
|
||||
<span
|
||||
className="ms-Button-textContainer textContainer-4"
|
||||
>
|
||||
<span
|
||||
className="ms-Button-label label-6"
|
||||
id="id__0"
|
||||
>
|
||||
Manage Cookies unavailable
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`storybook snapshot tests Storyshots UI Components/GridLayout Grid Layout Component 1`] = `
|
||||
<div
|
||||
className="css-75 root-0 body-1"
|
||||
|
|
|
@ -25,6 +25,6 @@
|
|||
"isolatedModules": true,
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"include": ["stories/**/*"],
|
||||
"include": ["stories/**/*", "./.storybook/**/*.test.ts"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче