Skip to content

Commit

Permalink
MAN-256: Added Click Analytics (#268)
Browse files Browse the repository at this point in the history
* MAN-256: Added Click Analytics
---------

Co-authored-by: Neil Mills <[email protected]>
  • Loading branch information
pmcphee77 and neil-mills authored Jan 16, 2025
1 parent 92fd1eb commit 49af9e5
Show file tree
Hide file tree
Showing 52 changed files with 4,089 additions and 2,625 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
"text": "🛡️ *Manage a Supervision* ZAP report"
"text": "🛡️ *Manage people on probation probation* ZAP report"
}
},
{
Expand Down Expand Up @@ -131,7 +131,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
"text": "❌ Failed to generate *Manage a Supervision* ZAP report"
"text": "❌ Failed to generate *Manage people on probation* ZAP report"
}
},
{
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ Also add the FLIPT_URL for dev to your .env file
FLIPT_URL="https://feature-flags-dev.hmpps.service.justice.gov.uk"
```


## Formatting

### Check formatting
Expand Down
59 changes: 59 additions & 0 deletions assets/js/appInsights.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint-disable no-param-reassign */
/* eslint-disable no-console */

import { ApplicationInsights } from '@microsoft/applicationinsights-web'
import { ClickAnalyticsPlugin } from '@microsoft/applicationinsights-clickanalytics-js'

document.initialiseTelemetry = (applicationInsightsConnectionString, applicationInsightsRoleName, userName) => {
if (!applicationInsightsConnectionString) {
console.log('AppInsights not configured')
return
}

console.log('Configuring AppInsights')

const clickPluginInstance = new ClickAnalyticsPlugin()
const contentName = element => {
const id = element.getAttribute('data-ai-id')
if (id && id.includes('PersonName')) {
return '<Persons Name>'
}
const uri = element.getAttribute('title')
if (uri && uri.includes('Select case record')) {
return 'searchPersonNameLink'
}
return ''
}
const clickPluginConfig = {
autoCapture: true,
dropInvalidEvents: true,
dataTags: {
customDataPrefix: 'data-ai-',
useDefaultContentNameOrId: true,
},
callback: {
contentName,
},
}

const appInsights = new ApplicationInsights({
config: {
disableXhr: true,
connectionString: applicationInsightsConnectionString,
autoTrackPageVisitTime: true,
extensions: [clickPluginInstance],
extensionConfig: {
[clickPluginInstance.identifier]: clickPluginConfig,
},
},
})

const telemetryInitializer = envelope => {
envelope.tags['ai.cloud.role'] = applicationInsightsRoleName
envelope.tags['ai.user.id'] = userName
}

appInsights.loadAppInsights()
appInsights.addTelemetryInitializer(telemetryInitializer)
appInsights.trackPageView()
}
4 changes: 0 additions & 4 deletions assets/js/govukFrontendInit.js

This file was deleted.

9 changes: 9 additions & 0 deletions assets/js/application.js → assets/js/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import * as govukFrontend from 'govuk-frontend'
import * as mojFrontend from '@ministryofjustice/frontend'
import './appInsights'
import './backendSortableTable'
import './predictors'

govukFrontend.initAll()
mojFrontend.initAll()

/* eslint-disable no-restricted-globals */
const lastAppointment = () => {
const repeatingFrequency = document.querySelector('div[data-repeating-frequency]')
Expand Down
8 changes: 0 additions & 8 deletions assets/js/mojFrontendInit.js

This file was deleted.

8 changes: 4 additions & 4 deletions assets/scss/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ $path: '/assets/images/';
$moj-page-width: 1170px;
$govuk-page-width: $moj-page-width;

@import 'govuk/all';
@import 'moj/all';
@import '../../node_modules/govuk-frontend/dist/govuk/all';
@import '../../node_modules/@ministryofjustice/frontend/moj/all';

@import './components/header-bar';
@import './components/summary-card';
@import './components/card';
@import 'assets/scss/local';
@import './components/sortable-table';
@import "../../node_modules/govuk-frontend/dist/govuk/base";
@import "../../node_modules/@ministryofjustice/frontend/moj/components/sortable-table/_sortable-table";
@import '../../node_modules/govuk-frontend/dist/govuk/base';
@import '../../node_modules/@ministryofjustice/frontend/moj/components/sortable-table/_sortable-table';
@import './components/mappa-widget';
@import './components/predictor-scores';
@import './components/risk-flag-widget';
Expand Down
2 changes: 1 addition & 1 deletion e2e_tests/steps/mas/personal-details/personalDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const searchForCrn = async (page: Page, crn: string) => {
await page.getByLabel('Find a person on probation').fill(crn)
await page.getByRole('button', { name: 'Search' }).click()
await page.locator(`[href$="${crn}"]`).click()
await expect(page).toHaveTitle('Manage a Supervision - Overview')
await expect(page).toHaveTitle('Manage people on probation - Overview')
}

export const assertAddressDetails = async (
Expand Down
30 changes: 30 additions & 0 deletions esbuild/app.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable no-console */
const { copy } = require('esbuild-plugin-copy')
const { typecheckPlugin } = require('@jgoz/esbuild-plugin-typecheck')
const esbuild = require('esbuild')
const glob = require('glob')
const pkg = require('../package.json')

const buildApp = buildConfig =>
esbuild.build({
entryPoints: glob.sync(buildConfig.app.entryPoints),
outdir: buildConfig.app.outDir,
bundle: true,
sourcemap: buildConfig.sourcemap,
platform: 'node',
format: 'cjs',
external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})],
plugins: [
typecheckPlugin(),
copy({
resolveFrom: 'cwd',
assets: buildConfig.app.copy,
}),
],
})

module.exports = buildConfig => {
console.log('\u{1b}[1m\u{2728} Building app...\u{1b}[0m')

return buildApp(buildConfig)
}
47 changes: 47 additions & 0 deletions esbuild/assets.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable no-console */

const { copy } = require('esbuild-plugin-copy')
const { sassPlugin } = require('esbuild-sass-plugin')
const { clean } = require('esbuild-plugin-clean')
const esbuild = require('esbuild')
const path = require('path')
const { glob } = require('glob')

const buildAdditionalAssets = buildConfig =>
esbuild.build({
outdir: buildConfig.assets.outDir,
plugins: [
copy({
resolveFrom: 'cwd',
assets: buildConfig.assets.copy,
}),
],
})

const buildAssets = buildConfig =>
esbuild.build({
entryPoints: buildConfig.assets.entryPoints,
outdir: buildConfig.assets.outDir,
entryNames: '[ext]/app',
minify: buildConfig.isProduction,
sourcemap: buildConfig.sourcemap,
platform: 'browser',
target: 'es2018',
external: ['/assets/*'],
bundle: true,
plugins: [
clean({
patterns: glob.sync(buildConfig.assets.clear),
}),
sassPlugin({
quietDeps: true,
loadPaths: [process.cwd(), path.join(process.cwd(), 'node_modules')],
}),
],
})

module.exports = buildConfig => {
console.log('\u{1b}[1m\u{2728} Building assets...\u{1b}[0m')

return Promise.all([buildAssets(buildConfig), buildAdditionalAssets(buildConfig)])
}
94 changes: 94 additions & 0 deletions esbuild/esbuild.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies */
const path = require('path')
const { glob } = require('glob')
const chokidar = require('chokidar')
const { spawn } = require('child_process')
const buildAssets = require('./assets.config')
const buildApp = require('./app.config')

const nwDir = path.dirname(process.execPath)

const cwd = process.cwd()
const buildConfig = {
isProduction: process.env.NODE_ENV === 'production',
sourcemap: process.env.NODE_ENV === 'development' ? 'inline' : false,
app: {
outDir: path.join(cwd, 'dist'),
entryPoints: path.join(cwd, 'server.ts'),
copy: [
{
from: path.join(cwd, 'server/views/**/*'),
to: path.join(cwd, 'dist/server/views'),
},
],
},

assets: {
outDir: path.join(cwd, 'dist/assets'),
entryPoints: glob.sync([path.join(cwd, 'assets/js/index.js'), path.join(cwd, 'assets/scss/application.scss')]),
copy: [
{
from: path.join(cwd, 'assets/images/**/*'),
to: path.join(cwd, 'dist/assets/images'),
},
{
from: path.join(cwd, 'package.json'),
to: path.join(cwd, 'dist/package.json'),
},
],
clear: glob.sync([path.join(cwd, 'dist/assets/{css,js}')]),
},
}

function main() {
const chokidarOptions = {
persistent: true,
ignoreInitial: true,
}

const args = process.argv

if (args.includes('--build')) {
Promise.all([buildApp(buildConfig), buildAssets(buildConfig)]).catch(() => process.exit(1))
}

if (args.includes('--feature-dev-server')) {
let serverProcess = null
chokidar.watch(['dist']).on('all', () => {
if (serverProcess) serverProcess.kill()
serverProcess = spawn(
`${nwDir}/node`,
['--inspect=0.0.0.0', '--enable-source-maps', 'dist/server.js', ' | bunyan -o short'],
{
stdio: 'inherit',
},
)
})
}
if (args.includes('--dev-server')) {
let serverProcess = null
chokidar.watch(['dist']).on('all', () => {
if (serverProcess) serverProcess.kill()
serverProcess = spawn(
`${nwDir}/node`,
['--inspect=0.0.0.0', '--enable-source-maps', '-r', 'dotenv/config', 'dist/server.js', ' | bunyan -o short'],
{
stdio: 'inherit',
},
)
})
}

if (args.includes('--watch')) {
console.log('\u{1b}[1m\u{1F52D} Watching for changes...\u{1b}[0m')
// Assets
chokidar.watch(['assets/**/*'], chokidarOptions).on('all', () => buildAssets(buildConfig).catch(console.error))

// App
chokidar
.watch(['server/**/*', 'app/**/*'], { ...chokidarOptions, ignored: ['**/*.test.ts'] })
.on('all', () => buildApp(buildConfig).catch(console.error))
}
}
main()
2 changes: 1 addition & 1 deletion logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import config from './server/config'

const formatOut = bunyanFormat({ outputMode: 'short', color: !config.production })

const logger = bunyan.createLogger({ name: 'Manage a Supervision', stream: formatOut, level: 'debug' })
const logger = bunyan.createLogger({ name: 'Manage people on probation', stream: formatOut, level: 'debug' })

export default logger
Loading

0 comments on commit 49af9e5

Please sign in to comment.