Skip to content

Commit

Permalink
feat(matomo): upgrade to mui v5
Browse files Browse the repository at this point in the history
- added `secure` flag to matomo-backend plugin
- use backstage fetchApi for new backend system

Signed-off-by: Yash Oswal <[email protected]>
  • Loading branch information
yashoswalyo committed May 21, 2024
1 parent 566dc8c commit 802623e
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 140 deletions.
4 changes: 4 additions & 0 deletions plugins/matomo-backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,9 @@ Add the following configurations into your `app-config.yaml` file:
```yaml
matomo:
apiToken: ${MATOMO_API_TOKEN}

apiUrl: ${MATOMO_API_URL}

# (OPTIONAL) Set to false if you get SSL certificate error
secure: ${MATOMO_SECURE_FLAG}
```
2 changes: 2 additions & 0 deletions plugins/matomo-backend/app-config.janus-idp.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
matomo:
apiToken: ${MATOMO_API_TOKEN}
apiUrl: ${MATOMO_API_URL}
# Set to false if you get SSL certificate error
secure: ${MATOMO_SECURE_FLAG}
5 changes: 5 additions & 0 deletions plugins/matomo-backend/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@ export interface Config {
* @visibility backend
*/
apiUrl: string;
/**
* Set to false if you get SSL certificate error
* @visibility backend
*/
secure: boolean;
};
}
4 changes: 1 addition & 3 deletions plugins/matomo-backend/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/

import { loggerToWinstonLogger } from '@backstage/backend-common';
import {
coreServices,
createBackendPlugin,
Expand All @@ -32,9 +31,8 @@ export const matomoBackendPlugin = createBackendPlugin({
config: coreServices.rootConfig,
},
async init({ http, logger, config }) {
const winstonLogger = loggerToWinstonLogger(logger);
logger.info('Matomo plugin is running');
const router = await createRouter({
logger: winstonLogger,
config,
});
http.use(router);
Expand Down
10 changes: 5 additions & 5 deletions plugins/matomo-backend/src/service/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import { Config } from '@backstage/config';
import express from 'express';
import Router from 'express-promise-router';
import { createProxyMiddleware } from 'http-proxy-middleware';
import { Logger } from 'winston';

export interface RouterOptions {
logger: Logger;
config: Config;
}

Expand All @@ -18,9 +16,10 @@ export async function createRouter(

const matomoToken = config.getString('matomo.apiToken');
const matomoApiUrl = config.getString('matomo.apiUrl');
const isSecure = config.getOptionalBoolean('matomo.secure');
if (!matomoToken || !matomoApiUrl) {
throw new Error(
'Missing matomo config in app-config.yaml. Add matomo.apiToken and apiUrl in config',
'Missing matomo config in app-config.yaml. Add matomo.apiToken and matomo.apiUrl in config',
);
}

Expand All @@ -30,7 +29,7 @@ export async function createRouter(
if (req.method === 'POST' && req.body) {
const params = new URLSearchParams(req.body);
const method = params.get('method');
if (!method || !method.includes('.get')) {
if (!method?.includes('.get')) {
res.status(400).json({ message: 'read only operation' });
return;
}
Expand All @@ -45,13 +44,14 @@ export async function createRouter(
createProxyMiddleware({
target: matomoApiUrl,
changeOrigin: true,
secure: isSecure ?? true,
onProxyReq: (proxyReq, req) => {
proxyReq.setHeader('Content-Type', 'application/x-www-form-urlencoded');
proxyReq.setHeader('Content-Length', Buffer.byteLength(req.body));
proxyReq.write(req.body);
},
pathRewrite: {
'^/api/matomo': '/',
['/api/matomo']: '/',
},
}),
);
Expand Down
1 change: 0 additions & 1 deletion plugins/matomo-backend/src/service/standaloneServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export async function startStandaloneServer(

logger.debug('Starting application server...');
const router = await createRouter({
logger,
config,
});

Expand Down
2 changes: 1 addition & 1 deletion plugins/matomo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The matomo plugin shows the basic analytics from [Matomo](https://matomo.org/)
1. Install the plugin

```bash
yarn add @janus-idp/plugin-matomo
yarn workspace app add @janus-idp/backstage-plugin-matomo
```

2. Make sure the [Matomo backend plugin](../matomo-backend/README.md) is installed and configured
Expand Down
2 changes: 2 additions & 0 deletions plugins/matomo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "^4.0.0-alpha.45",
"@mui/icons-material": "^5.15.18",
"@mui/material": "^5.15.18",
"@tanstack/react-query": "^4.36.1",
"axios": "^1.6.0",
"react-use": "^17.4.0",
Expand Down
150 changes: 84 additions & 66 deletions plugins/matomo/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConfigApi, createApiRef } from '@backstage/core-plugin-api';
import { ConfigApi, createApiRef, FetchApi } from '@backstage/core-plugin-api';

import {
TActionByPageURLMetrics,
Expand Down Expand Up @@ -47,6 +47,7 @@ export type MatomoAPI = {

type Options = {
configApi: ConfigApi;
fetchApi: FetchApi;
};

export const matomoApiRef = createApiRef<MatomoAPI>({
Expand Down Expand Up @@ -75,9 +76,11 @@ export const transformVisitByTime = (

export class MatomoApiClient implements MatomoAPI {
private readonly configApi: ConfigApi;
private readonly fetchApi: FetchApi;

constructor(options: Options) {
this.configApi = options.configApi;
this.fetchApi = options.fetchApi;
}

async getUserVisitMetrics(
Expand All @@ -86,20 +89,23 @@ export class MatomoApiClient implements MatomoAPI {
date: string,
): Promise<TUserVisitMetrics> {
const backendUrl = this.configApi.getString('backend.baseUrl');
const res = await fetch(`${backendUrl}/api/matomo?module=API&format=json`, {
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'VisitsSummary',
apiAction: 'get',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
const res = await this.fetchApi.fetch(
`${backendUrl}/api/matomo?module=API&format=json`,
{
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'VisitsSummary',
apiAction: 'get',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
},
});
);
return res.json();
}

Expand All @@ -109,20 +115,23 @@ export class MatomoApiClient implements MatomoAPI {
date: string,
): Promise<TGeoMetrics> {
const backendUrl = this.configApi.getString('backend.baseUrl');
const res = await fetch(`${backendUrl}/api/matomo?module=API&format=json`, {
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'UserCountry',
apiAction: 'getCountry',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
const res = await this.fetchApi.fetch(
`${backendUrl}/api/matomo?module=API&format=json`,
{
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'UserCountry',
apiAction: 'getCountry',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
},
});
);
return res.json();
}

Expand All @@ -132,20 +141,23 @@ export class MatomoApiClient implements MatomoAPI {
date: string,
): Promise<TDeviceMetrics> {
const backendUrl = this.configApi.getString('backend.baseUrl');
const res = await fetch(`${backendUrl}/api/matomo?module=API&format=json`, {
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'DevicesDetection',
apiAction: 'getType',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
const res = await this.fetchApi.fetch(
`${backendUrl}/api/matomo?module=API&format=json`,
{
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'DevicesDetection',
apiAction: 'getType',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
},
});
);
return res.json();
}

Expand All @@ -161,20 +173,23 @@ export class MatomoApiClient implements MatomoAPI {
>
> {
const backendUrl = this.configApi.getString('backend.baseUrl');
const res = await fetch(`${backendUrl}/api/matomo?module=API&format=json`, {
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'Actions',
apiAction: 'getPageUrls',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
const res = await this.fetchApi.fetch(
`${backendUrl}/api/matomo?module=API&format=json`,
{
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'Actions',
apiAction: 'getPageUrls',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
},
});
);
const data = (await res.json()) as TActionByPageURLMetrics;
return data.reportData.map(({ bounce_rate, avg_time_on_page, ...el }) => {
const avgTimeStr = avg_time_on_page.split(':');
Expand All @@ -197,20 +212,23 @@ export class MatomoApiClient implements MatomoAPI {
date: string,
): Promise<Metric[]> {
const backendUrl = this.configApi.getString('backend.baseUrl');
const res = await fetch(`${backendUrl}/api/matomo?module=API&format=json`, {
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'Actions',
apiAction: 'get',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
const res = await this.fetchApi.fetch(
`${backendUrl}/api/matomo?module=API&format=json`,
{
method: 'POST',
body: new URLSearchParams({
idSite,
method: 'API.getProcessedReport',
period,
date,
apiModule: 'Actions',
apiAction: 'get',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
},
});
);
const { reportData, columns } = (await res.json()) as TActionMetrics;
return Object.keys(columns).map(metric => ({
metric: columns[metric as keyof TActionMetrics['reportData']],
Expand Down
28 changes: 13 additions & 15 deletions plugins/matomo/src/components/MatomoPage/MatomoPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,19 @@ import {
import { configApiRef, useApi } from '@backstage/core-plugin-api';
import { useEntity } from '@backstage/plugin-catalog-react';

import {
Box,
Card,
CardContent,
CircularProgress,
FormControl,
Grid,
InputLabel,
MenuItem,
Tooltip as MuiTooltip,
Select,
Typography,
} from '@material-ui/core';
import Assessment from '@material-ui/icons/Assessment';
import ContactMail from '@material-ui/icons/ContactMail';
import Assessment from '@mui/icons-material/Assessment';
import ContactMail from '@mui/icons-material/ContactMail';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CircularProgress from '@mui/material/CircularProgress';
import FormControl from '@mui/material/FormControl';
import Grid from '@mui/material/Grid';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import MuiTooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import {
CartesianGrid,
Expand Down
10 changes: 4 additions & 6 deletions plugins/matomo/src/components/MatomoPage/StatsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React, { ReactNode } from 'react';

import {
Card,
CardContent,
CircularProgress,
Typography,
} from '@material-ui/core';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CircularProgress from '@mui/material/CircularProgress';
import Typography from '@mui/material/Typography';

type Props = {
title: string;
Expand Down
Loading

0 comments on commit 802623e

Please sign in to comment.