Skip to content

Commit

Permalink
feat: GEO-1121 Single analytics powerBi report with error notificatio…
Browse files Browse the repository at this point in the history
…ns. (#783)
  • Loading branch information
jer3k authored Sep 26, 2024
1 parent 7d53a4c commit 1cfd64e
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 51 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/.deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ jobs:
--set-string global.secrets.s3Endpoint="${{secrets.S3_ENDPOINT }}" \
--set-string global.secrets.s3Bucket="${{secrets.S3_BUCKET }}" \
--set-string global.secrets.powerBiAnalyticsWorkspaceId="${{secrets.POWERBI_ANALYTICS_WORKSPACE_ID }}" \
--set-string global.secrets.powerBiAnalyticsSubmissionAnalyticsId="${{secrets.POWERBI_ANALYTICS_SUBMISSIONANALYTICS_ID }}" \
--set-string global.secrets.powerBiAnalyticsUserBehaviourId="${{secrets.POWERBI_ANALYTICS_USERBEHAVIOUR_ID }}" \
--set-string global.secrets.powerBiAnalyticsDataAnalyticsId="${{secrets.POWERBI_ANALYTICS_DATAANALYTICS_ID }}" \
--set-string global.secrets.powerBiAnalyticsReportId="${{secrets.POWERBI_ANALYTICS_REPORT_ID }}" \
--set-string global.serverAdminFrontend="${{ inputs.admin-frontend-url }}" \
--set-string global.serverFrontend="${{ inputs.frontend-url }}" \
--set-string crunchy.pgBackRest.s3.bucket="${{ secrets.S3_BUCKET }}" \
Expand Down
32 changes: 22 additions & 10 deletions admin-frontend/src/components/AnalyticsPage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-if="isAnalyticsAvailable">
<div v-if="isAnalyticsAvailable" class="w-100 overflow-x-auto">
<div
v-for="[name, details] in resourceDetails"
:key="name"
Expand All @@ -20,10 +20,11 @@
import { PowerBIReportEmbed } from 'powerbi-client-vue-js';
import { EventHandler } from 'powerbi-client-vue-js/dist/types/src/utils/utils';
import { models, IReportEmbedConfiguration, Report } from 'powerbi-client';
import { reactive, CSSProperties } from 'vue';
import { reactive, CSSProperties, Reactive } from 'vue';
import ApiService from '../services/apiService';
import { ZonedDateTime, Duration } from '@js-joda/core';
import { POWERBI_RESOURCE } from '../utils/constant';
import { NotificationService } from '../services/notificationService';
type PowerBiDetails = {
config: IReportEmbedConfiguration;
Expand All @@ -36,17 +37,17 @@ const isAnalyticsAvailable =
(window as any).config?.IS_ADMIN_ANALYTICS_AVAILABLE?.toUpperCase() == 'TRUE';
const resourceDetails = createDefaultPowerBiDetailsMap([
POWERBI_RESOURCE.SUBMISSIONANALYTICS,
POWERBI_RESOURCE.USERBEHAVIOUR,
POWERBI_RESOURCE.DATAANALYTICS,
POWERBI_RESOURCE.ANALYTICS,
]);
if (isAnalyticsAvailable) {
getPowerBiAccessToken(resourceDetails);
}
/** Create a Map containing the details of the resources. */
function createDefaultPowerBiDetailsMap(resourcesToLoad: POWERBI_RESOURCE[]) {
function createDefaultPowerBiDetailsMap(
resourcesToLoad: POWERBI_RESOURCE[],
): Reactive<Map<POWERBI_RESOURCE, PowerBiDetails>> {
const resourceDetails = reactive(new Map<POWERBI_RESOURCE, PowerBiDetails>());
for (const name of resourcesToLoad) {
Expand Down Expand Up @@ -97,10 +98,21 @@ function createDefaultPowerBiDetailsMap(resourcesToLoad: POWERBI_RESOURCE[]) {
* Get the embed config from the service.
* Auto refresh the token before it expires.
*/
async function getPowerBiAccessToken(resourceDetails) {
const embedInfo = await ApiService.getPowerBiEmbedAnalytics(
Array.from(resourceDetails.keys()),
);
async function getPowerBiAccessToken(
resourceDetails: Reactive<Map<POWERBI_RESOURCE, PowerBiDetails>>,
) {
let embedInfo;
try {
embedInfo = await ApiService.getPowerBiEmbedAnalytics(
Array.from(resourceDetails.keys()),
);
} catch (err) {
NotificationService.pushNotificationError(
'Analytics failed to load. Please try again later or contact the helpdesk.',
undefined,
1000 * 60 * 3,
);
}
for (let resource of embedInfo.resources) {
const ref = resourceDetails.get(resource.name);
if (!ref) continue;
Expand Down
4 changes: 1 addition & 3 deletions admin-frontend/src/utils/constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,5 @@ export const REPORT_STATUS = Object.freeze({
});

export const POWERBI_RESOURCE = Object.freeze({
SUBMISSIONANALYTICS: 'SubmissionAnalytics',
USERBEHAVIOUR: 'UserBehaviour',
DATAANALYTICS: 'DataAnalytics',
ANALYTICS: 'Analytics',
});
5 changes: 1 addition & 4 deletions backend/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@ config.defaults({
powerBiUrl: process.env.BACKEND_POWERBI_URL,
analytics: {
workspaceId: process.env.POWERBI_ANALYTICS_WORKSPACE_ID,
submissionAnalyticsId:
process.env.POWERBI_ANALYTICS_SUBMISSIONANALYTICS_ID,
userBehaviourId: process.env.POWERBI_ANALYTICS_USERBEHAVIOUR_ID,
dataAnalyticsId: process.env.POWERBI_ANALYTICS_DATAANALYTICS_ID,
analyticsId: process.env.POWERBI_ANALYTICS_REPORT_ID,
},
},
s3: {
Expand Down
13 changes: 4 additions & 9 deletions backend/src/v1/routes/analytic-routes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,15 @@ describe('analytics', () => {
mockGetEmbedInfo.mockReturnValue({});

it('should return 200', async () => {
await request(app)
.get('/embed?resources[]=SubmissionAnalytics')
.expect(200);
expect(mockGetEmbedInfo).toHaveBeenCalledWith(['SubmissionAnalytics']);
await request(app).get('/embed?resources[]=Analytics').expect(200);
expect(mockGetEmbedInfo).toHaveBeenCalledWith(['Analytics']);
});

it('should allow multiple resource names', async () => {
await request(app)
.get('/embed?resources[]=SubmissionAnalytics&resources[]=DataAnalytics')
.get('/embed?resources[]=Analytics&resources[]=Analytics')
.expect(200);
expect(mockGetEmbedInfo).toHaveBeenCalledWith([
'SubmissionAnalytics',
'DataAnalytics',
]);
expect(mockGetEmbedInfo).toHaveBeenCalledWith(['Analytics', 'Analytics']);
});

it('should return 500 if invalid resource name provided', async () => {
Expand Down
17 changes: 11 additions & 6 deletions backend/src/v1/services/analytic-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ describe('getEmbedInfo', () => {
jest.clearAllMocks();
});

it('should return json', async () => {
it('should return json when given multiple resources to embed', async () => {
const output: PowerBiEmbedInfo = {
resources: [
{
name: PowerBiResourceName.SubmissionAnalytics,
name: PowerBiResourceName.Analytics,
id: '123',
embedUrl: 'foo.bar.ca',
},
{
name: PowerBiResourceName.DataAnalytics,
name: PowerBiResourceName.Analytics,
id: '123',
embedUrl: 'foo.bar.ca',
},
Expand All @@ -48,15 +48,20 @@ describe('getEmbedInfo', () => {
embedToken: { token: output.accessToken, expiration: output.expiry },
});
const json = await analyticsService.getEmbedInfo([
PowerBiResourceName.SubmissionAnalytics,
PowerBiResourceName.DataAnalytics,
PowerBiResourceName.Analytics,
PowerBiResourceName.Analytics,
]);
expect(mockGetEmbedParamsForReports).toHaveBeenCalledTimes(1);
expect(json).toMatchObject(output);
});

it('should throw error if invalid resource names', async () => {
await expect(analyticsService.getEmbedInfo([PowerBiResourceName.SubmissionAnalytics, 'invalid' as any])).rejects.toThrow('Invalid resource names');
await expect(
analyticsService.getEmbedInfo([
PowerBiResourceName.Analytics,
'invalid' as never,
]),
).rejects.toThrow('Invalid resource names');
expect(mockGetEmbedParamsForReports).not.toHaveBeenCalled();
});
});
16 changes: 3 additions & 13 deletions backend/src/v1/services/analytic-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,13 @@ export type PowerBiEmbedInfo = {
};

export enum PowerBiResourceName {
SubmissionAnalytics = 'SubmissionAnalytics',
UserBehaviour = 'UserBehaviour',
DataAnalytics = 'DataAnalytics',
Analytics = 'Analytics',
}

const resourceIds: Record<PowerBiResourceName, ReportInWorkspace> = {
SubmissionAnalytics: {
Analytics: {
workspaceId: config.get('powerbi:analytics:workspaceId'),
reportId: config.get('powerbi:analytics:submissionAnalyticsId'),
},
UserBehaviour: {
workspaceId: config.get('powerbi:analytics:workspaceId'),
reportId: config.get('powerbi:analytics:userBehaviourId'),
},
DataAnalytics: {
workspaceId: config.get('powerbi:analytics:workspaceId'),
reportId: config.get('powerbi:analytics:dataAnalyticsId'),
reportId: config.get('powerbi:analytics:analyticsId'),
},
};

Expand Down
4 changes: 1 addition & 3 deletions charts/fin-pay-transparency/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ data:
ENTRA_APP_TENANT_ID: {{ .Values.global.secrets.entraTenantId | b64enc | quote }}
BACKEND_POWERBI_URL: {{ .Values.global.secrets.powerBiUrl | b64enc | quote }}
POWERBI_ANALYTICS_WORKSPACE_ID: {{ .Values.global.secrets.powerBiAnalyticsWorkspaceId | b64enc | quote }}
POWERBI_ANALYTICS_SUBMISSIONANALYTICS_ID: {{ .Values.global.secrets.powerBiAnalyticsSubmissionAnalyticsId | b64enc | quote }}
POWERBI_ANALYTICS_USERBEHAVIOUR_ID: {{ .Values.global.secrets.powerBiAnalyticsUserBehaviourId | b64enc | quote }}
POWERBI_ANALYTICS_DATAANALYTICS_ID: {{ .Values.global.secrets.powerBiAnalyticsDataAnalyticsId | b64enc | quote }}
POWERBI_ANALYTICS_REPORT_ID: {{ .Values.global.secrets.powerBiAnalyticsReportId | b64enc | quote }}
S3_ACCESS_KEY_ID: {{ .Values.global.secrets.s3AccessKeyId | b64enc | quote }}
S3_SECRET_ACCESS_KEY: {{ .Values.global.secrets.s3SecretAccessKey | b64enc | quote }}
S3_BUCKET_NAME: {{ .Values.global.secrets.s3Bucket | b64enc | quote }}
Expand Down

0 comments on commit 1cfd64e

Please sign in to comment.