Skip to content

Commit

Permalink
Google analytics integration in the new webgui (Ericsson#642)
Browse files Browse the repository at this point in the history
  • Loading branch information
LoremIPsummer authored and mozesl committed Nov 1, 2023
1 parent b146272 commit 15dae6a
Show file tree
Hide file tree
Showing 14 changed files with 316 additions and 4 deletions.
6 changes: 6 additions & 0 deletions webgui-new/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions webgui-new/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"react": "^18.2.0",
"react-diff-viewer-continued": "^3.2.6",
"react-dom": "^18.2.0",
"react-ga4": "^2.1.0",
"react-i18next": "^13.0.1",
"react-icons": "^4.8.0",
"react-toastify": "^9.1.2",
Expand Down
9 changes: 8 additions & 1 deletion webgui-new/src/components/codebites/codebites-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { IconButton, Tooltip } from '@mui/material';
import { Close } from '@mui/icons-material';
import { AppContext } from 'global-context/app-context';
import dagre from 'dagre';
import { sendGAEvent } from 'utils/analytics';

type CodeBitesElement = {
astNodeInfo: AstNodeInfo;
Expand Down Expand Up @@ -94,6 +95,7 @@ class CustomOffsetGutterMarker extends GutterMarker {

export const CodeBitesNode = ({ data }: NodeProps<DataProps>): JSX.Element => {
const { diagramGenId: initialNodeId } = useContext(AppContext);
const appCtx = useContext(AppContext);
const { theme } = useContext(ThemeContext);

const [fileInfo, setFileInfo] = useState<FileInfo | undefined>(undefined);
Expand All @@ -108,11 +110,16 @@ export const CodeBitesNode = ({ data }: NodeProps<DataProps>): JSX.Element => {
const init = async () => {
const initFileInfo = await getFileInfo(data.astNodeInfo.range?.file as string);
const initText = await getCppSourceText(data.astNodeInfo.id as string);
sendGAEvent({
event_action: 'code_bites',
event_category: appCtx.workspaceId,
event_label: `${initFileInfo?.name}: ${initText}`,
});
setFileInfo(initFileInfo);
setText(initText);
};
init();
}, [data.astNodeInfo]);
}, [appCtx.workspaceId, data.astNodeInfo]);

const handleClick = async () => {
if (!editorRef.current) return;
Expand Down
11 changes: 11 additions & 0 deletions webgui-new/src/components/codemirror-editor/codemirror-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { RouterQueryType } from 'utils/types';
import { Tooltip, alpha } from '@mui/material';
import * as SC from './styled-components';
import { useTranslation } from 'react-i18next';
import { sendGAEvent } from 'utils/analytics';

export const CodeMirrorEditor = (): JSX.Element => {
const { t } = useTranslation();
Expand Down Expand Up @@ -111,6 +112,11 @@ export const CodeMirrorEditor = (): JSX.Element => {
? null
: await getCppAstNodeInfoByPosition(fileInfo?.id as string, line.number, column);
if (astNodeInfo) {
sendGAEvent({
event_action: 'click_on_word',
event_category: appCtx.workspaceId,
event_label: `${fileInfo?.name}: ${astNodeInfo.astNodeValue}`,
});
dispatchSelection(astNodeInfo?.range?.range as Range);
router.push({
pathname: '/project',
Expand All @@ -132,6 +138,11 @@ export const CodeMirrorEditor = (): JSX.Element => {
column: line.length + 1,
}),
});
sendGAEvent({
event_action: 'click_on_word',
event_category: appCtx.workspaceId,
event_label: `${fileInfo?.name}: ${convertSelectionRangeToString(range)}`,
});
dispatchSelection(range);
router.push({
pathname: '/project',
Expand Down
186 changes: 186 additions & 0 deletions webgui-new/src/components/cookie-notice/cookie-notice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { getStore, setStore } from 'utils/store';
import ReactGA from 'react-ga4';
import {
Paper,
Typography,
Button,
IconButton,
Snackbar,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TableContainer,
TableRow,
TableCell,
Table,
TableHead,
TableBody,
Link,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import { useRouter } from 'next/router';

export const CookieNotice = (): JSX.Element => {
const { t } = useTranslation();
const router = useRouter();
const [isCookieConsent, setIsCookieConsent] = useState<boolean | undefined>(undefined);
const [gaTrackingCode, setGaTrackingCode] = useState<string | undefined>(undefined);
const [openPolicyModal, setOpenPolicyModal] = useState(false);
const [showNoticeSnackbar, setShowNoticeSnackbar] = useState(true);

useEffect(() => {
const fetchGaTrackingCode = async () => {
try {
const res = await fetch(`/ga.txt`);
if (res.status !== 200) {
setGaTrackingCode(undefined);
return;
}
const gaCode = await res.text();
setGaTrackingCode(gaCode);
} catch (e) {
// network-related error
setGaTrackingCode(undefined);
}
const store = getStore();
setIsCookieConsent(store.storedCookieConsent);
};
fetchGaTrackingCode();
}, []);

useEffect(() => {
if (!isCookieConsent || !gaTrackingCode) {
ReactGA.reset();
return;
}
if (!ReactGA.isInitialized) {
ReactGA.initialize(gaTrackingCode);
console.log(`Google Analytics initialized - ${gaTrackingCode}`);
}

const handleRouteChange = (url: string) => {
ReactGA.send({ hitType: 'pageview', page: url, title: window.document.title });
};
router.events.on('routeChangeComplete', handleRouteChange);

return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [isCookieConsent, gaTrackingCode, router.events]);

const handleCookieAccept = () => {
setIsCookieConsent(true);
setShowNoticeSnackbar(false);
setStore({ storedCookieConsent: true });
};

if (!isCookieConsent && gaTrackingCode)
return (
<>
<Snackbar
open={showNoticeSnackbar}
autoHideDuration={null}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Paper
sx={{
p: 2,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Typography variant="body2">
{t('cookie.INTRO_TEXT')}
<Button color="primary" size="small" onClick={() => setOpenPolicyModal(true)}>
{t('cookie.LEARN_MORE')}
</Button>
</Typography>
<Button
color="primary"
size="small"
variant="contained"
onClick={() => {
handleCookieAccept();
}}
>
{t('cookie.ACCEPT')}
</Button>
<IconButton
size="small"
color="inherit"
sx={{ ml: 2 }}
onClick={() => setShowNoticeSnackbar(false)}
>
<CloseIcon fontSize="small" />
</IconButton>
</Paper>
</Snackbar>
<Dialog open={openPolicyModal} maxWidth="lg" onClose={() => setOpenPolicyModal(false)}>
<DialogTitle>{t('cookiePolicy.TITLE')}</DialogTitle>
<DialogContent>
<>
<Typography sx={{ marginBottom: '0.8rem' }} variant="body1">
{t('cookiePolicy.sections.cookies.WHAT_COOKIES')}
</Typography>
<Typography sx={{ marginBottom: '0.8rem' }} variant="body2">
{t('cookiePolicy.sections.cookies.WHAT_COOKIES_DESCRIPTION')}
</Typography>
<Typography sx={{ marginBottom: '0.8rem' }} variant="body1">
{t('cookiePolicy.sections.cookies.HOW_USE_TITLE')}
</Typography>
<TableContainer component={Paper} sx={{ marginBottom: '0.8rem' }}>
<Table sx={{ minWidth: 650 }} aria-label="cookie-table">
<TableHead>
<TableRow>
<TableCell>{t('cookiePolicy.sections.cookies.SERVICE')}</TableCell>
<TableCell>{t('cookiePolicy.sections.cookies.COOKIE_NAMES')}</TableCell>
<TableCell>{t('cookiePolicy.sections.cookies.DURATION')}</TableCell>
<TableCell>{t('cookiePolicy.sections.cookies.PURPOSE')}</TableCell>
<TableCell>{t('cookiePolicy.sections.cookies.MORE_INFORMATION')}</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow key={1} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
<TableCell component="th" scope="row">
<b>{t('cookiePolicy.sections.cookies.googleAnalytics.SERVICE')}</b>
</TableCell>
<TableCell>
<b>{t('cookiePolicy.sections.cookies.googleAnalytics.COOKIE_NAMES')}</b>
</TableCell>
<TableCell>
<b>{t('cookiePolicy.sections.cookies.googleAnalytics.DURATION')}</b>
</TableCell>
<TableCell>
<b>{t('cookiePolicy.sections.cookies.googleAnalytics.PURPOSE')}</b>
</TableCell>
<TableCell>
<Link
target="_blank"
rel="noreferrer"
href={t('cookiePolicy.sections.cookies.googleAnalytics.MORE_INFORMATION')}
>
<b>{t('cookiePolicy.sections.cookies.MORE_INFORMATION')}</b>
</Link>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
<Typography variant="body2">
{t('cookiePolicy.sections.cookies.CONCLUSION')}
</Typography>
</>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenPolicyModal(false)} color="primary"></Button>
</DialogActions>
</Dialog>
</>
);

return <></>;
};
16 changes: 14 additions & 2 deletions webgui-new/src/components/diagrams/diagrams.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { convertSelectionRangeToString } from 'utils/utils';
import { useRouter } from 'next/router';
import { RouterQueryType } from 'utils/types';
import { useTranslation } from 'react-i18next';
import { sendGAEvent } from 'utils/analytics';

export const Diagrams = (): JSX.Element => {
const { t } = useTranslation();
Expand Down Expand Up @@ -67,7 +68,18 @@ export const Diagrams = (): JSX.Element => {
: initDiagramInfo instanceof AstNodeInfo
? await getCppDiagram(appCtx.diagramGenId, parseInt(appCtx.diagramTypeId))
: '';


sendGAEvent({
event_action: `load_diagram: ${appCtx.diagramTypeId}`,
event_category: appCtx.workspaceId,
event_label:
initDiagramInfo instanceof FileInfo
? initDiagramInfo.name
: initDiagramInfo instanceof AstNodeInfo
? initDiagramInfo.astNodeValue
: '',
});

const parser = new DOMParser();
const parsedDiagram = parser.parseFromString(diagram, 'text/xml');
const diagramSvg = parsedDiagram.getElementsByTagName('svg')[0];
Expand All @@ -81,7 +93,7 @@ export const Diagrams = (): JSX.Element => {
setDiagramInfo(initDiagramInfo);
};
init();
}, [appCtx.diagramGenId, appCtx.diagramTypeId, appCtx.diagramType]);
}, [appCtx.diagramGenId, appCtx.diagramTypeId, appCtx.diagramType, appCtx.workspaceId]);

const generateDiagram = async (e: MouseEvent) => {
const parentNode = (e.target as HTMLElement)?.parentElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useRouter } from 'next/router';
import { RouterQueryType } from 'utils/types';
import { useTranslation } from 'react-i18next';
import { diagramTypeArray } from 'enums/entity-types';
import { sendGAEvent } from 'utils/analytics';

export const EditorContextMenu = ({
contextMenu,
Expand Down Expand Up @@ -69,8 +70,14 @@ export const EditorContextMenu = ({

const getDocs = async () => {
const initDocs = await getCppDocumentation(astNodeInfo?.id as string);
const fileInfo = await getFileInfo(appCtx.projectFileId as string);
const parser = new DOMParser();
const parsedHTML = parser.parseFromString(initDocs, 'text/html');
sendGAEvent({
event_action: 'documentation',
event_category: appCtx.workspaceId,
event_label: `${fileInfo?.name}: ${astNodeInfo?.astNodeValue}`,
});
setModalOpen(true);
setContextMenu(null);
if (!docsContainerRef.current) return;
Expand All @@ -87,6 +94,12 @@ export const EditorContextMenu = ({
const initAstHTML = await getAsHTMLForNode(astNodeInfo?.id as string);
const parser = new DOMParser();
const parsedHTML = parser.parseFromString(initAstHTML, 'text/html');
const fileInfo = await getFileInfo(appCtx.projectFileId as string);
sendGAEvent({
event_action: 'cpp_reparse_node',
event_category: appCtx.workspaceId,
event_label: `${fileInfo?.name}: ${astNodeInfo?.astNodeValue}`,
});
setModalOpen(true);
setContextMenu(null);
if (!astHTMLContainerRef.current) return;
Expand Down Expand Up @@ -115,6 +128,12 @@ export const EditorContextMenu = ({
}

const fileId = def.range?.file as string;
const fileInfo = await getFileInfo(appCtx.projectFileId as string);
sendGAEvent({
event_action: 'jump_to_def',
event_category: appCtx.workspaceId,
event_label: `${fileInfo?.name}: ${astNodeInfo.astNodeValue}`,
});

router.push({
pathname: '/project',
Expand Down Expand Up @@ -145,6 +164,11 @@ export const EditorContextMenu = ({
currentRepo?.repoPath as string,
fileInfo?.id as string
);
sendGAEvent({
event_action: 'git_blame',
event_category: appCtx.workspaceId,
event_label: fileInfo?.name,
});
return blameInfo;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useRouter } from 'next/router';
import { RouterQueryType } from 'utils/types';
import { useTranslation } from 'react-i18next';
import { diagramTypeArray } from 'enums/entity-types';
import { sendGAEvent } from 'utils/analytics';

export const FileContextMenu = ({
contextMenu,
Expand Down Expand Up @@ -67,6 +68,11 @@ export const FileContextMenu = ({
{fileInfo && fileInfo.isDirectory && (
<MenuItem
onClick={async () => {
sendGAEvent({
event_action: 'metrics',
event_category: appCtx.workspaceId,
event_label: fileInfo.name,
});
setContextMenu(null);
router.push({
pathname: '/project',
Expand Down
Loading

0 comments on commit 15dae6a

Please sign in to comment.