@ministryofjustice/hmpps-digital-prison-reporting-frontend 4.29.4 → 4.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dpr/components/_dashboards/dashboard-visualisation/types.js.map +2 -2
- package/dpr/components/_dashboards/dashboard-visualisation/types.ts +1 -0
- package/dpr/components/_dashboards/dashboard-visualisation/view.njk +12 -7
- package/dpr/components/_dashboards/scorecard/utils.js +3 -2
- package/dpr/components/_dashboards/scorecard/utils.js.map +2 -2
- package/dpr/components/_dashboards/scorecard/utils.test.ts +9 -1
- package/dpr/components/_dashboards/scorecard/utils.ts +2 -1
- package/dpr/components/user-reports/bookmarks/utils.js +2 -0
- package/dpr/components/user-reports/bookmarks/utils.js.map +2 -2
- package/dpr/components/user-reports/bookmarks/utils.ts +2 -0
- package/dpr/data/types.d.js.map +1 -1
- package/dpr/data/types.d.ts +0 -1
- package/dpr/routes/journeys/request-report/status/controller.js +2 -0
- package/dpr/routes/journeys/request-report/status/controller.js.map +2 -2
- package/dpr/routes/journeys/request-report/status/controller.ts +2 -0
- package/dpr/routes/journeys/view-report/async/controller.js +2 -0
- package/dpr/routes/journeys/view-report/async/controller.js.map +2 -2
- package/dpr/routes/journeys/view-report/async/controller.ts +2 -0
- package/dpr/routes/journeys/view-report/async/dashboard/tests.cy.js +27 -1
- package/dpr/routes/journeys/view-report/async/dashboard/tests.cy.js.map +2 -2
- package/dpr/routes/journeys/view-report/async/dashboard/tests.cy.ts +34 -1
- package/dpr/routes/journeys/view-report/async/dashboard/utils.js +46 -4
- package/dpr/routes/journeys/view-report/async/dashboard/utils.js.map +2 -2
- package/dpr/routes/journeys/view-report/async/dashboard/utils.ts +47 -2
- package/dpr/routes/journeys/view-report/sync/dashboard/utils.js +9 -1
- package/dpr/routes/journeys/view-report/sync/dashboard/utils.js.map +2 -2
- package/dpr/routes/journeys/view-report/sync/dashboard/utils.ts +9 -1
- package/dpr/services/featureFlagService.js +3 -3
- package/dpr/services/featureFlagService.js.map +2 -2
- package/dpr/services/featureFlagService.ts +10 -3
- package/package.json +1 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../dpr/components/_dashboards/dashboard-visualisation/types.ts"],
|
|
4
|
-
"sourcesContent": ["import z from 'zod'\nimport { components } from '../../../types/api'\nimport { Scorecard, ScorecardGroup } from '../scorecard/types'\nimport { MatrixChartData } from '../../_charts/chart/heatmap/types'\nimport { ChartDetails } from '../../../types/Charts'\nimport DashboardVisualisationSchemas from './Validate'\nimport { BarDefinitionMeasure } from '../../_charts/chart/bar/types'\nimport { DoughnutDefinitionMeasure } from '../../_charts/chart/doughnut/types'\nimport { LineDefinitionMeasure } from '../../_charts/chart/line/types'\nimport { LineTimeseriesDefinitionMeasure } from '../../_charts/chart/line-timeseries/types'\nimport { BarTimeseriesDefinitionMeasure } from '../../_charts/chart/bar-timeseries/types'\nimport { ChartOptionsType } from '../../_charts/chart/chart-config'\nimport { PartialDate } from '../../_filters/types'\n\nexport interface DashboardSection {\n id: string\n title?: string\n description?: string\n visualisations?: DashboardVisualisation[]\n}\n\nexport interface DashboardVisualisation {\n id: string\n type: components['schemas']['DashboardVisualisationDefinition']['type']\n title?: string | undefined\n description?: string | undefined\n data:\n | Scorecard\n | Scorecard[]\n | ScorecardGroup[]\n | DashboardVisualisatonCardData\n | DashboardVisualisationTable\n | undefined\n}\n\nexport interface DashboardVisualisatonCardData {\n chart?: DashboardVisualisationData | undefined\n table?: MoJTable | undefined\n details?: ChartDetails | undefined\n}\n\nexport interface DashboardVisualisationData {\n type: DashboardVisualisationType\n options?: DashboardVisualisationDataOptions\n data: DashboardVisualisationDataValues\n}\n\ninterface DashboardVisualisationDataOptions {\n height?: number\n unit?: components['schemas']['DashboardVisualisationColumnDefinition']['unit']\n timeseries?: boolean\n}\n\nexport interface DashboardVisualisationDataValues {\n labels?: string[]\n datasets: DashboardVisualisationDataSet[]\n axis?: 'x' | 'y'\n config: ChartOptionsType\n partialDate?: PartialDate | undefined\n}\n\nexport interface DashboardVisualisationDataSet {\n label: string\n data: number[] | MatrixChartData[]\n total?: number\n}\n\nexport interface DashboardVisualisationTable {\n table: MoJTable\n ts?: string\n}\n\nexport interface MoJTable {\n head: MoJTableHead[]\n rows: MoJTableRow[][]\n}\n\nexport interface MoJTableRow {\n text?: string\n html?: string\n}\n\nexport interface MoJTableHead {\n text?: string\n html?: string\n}\n\nexport enum DashboardVisualisationType {\n LIST = 'list',\n DONUT = 'doughnut',\n BAR = 'bar',\n LINE = 'line',\n MATRIX = 'matrix',\n MATRIX_TIMESERIES = 'matrix-timeseries',\n BAR_TIMESERIES = 'bar-timeseries',\n LINE_TIMESERIES = 'line-timeseries',\n SCORECARD = 'scorecard',\n SCORECARD_GROUP = 'scorecard-group',\n}\n\nexport type DashboardVisualisationOptions = ListDashboardVisualisationOptions | BucketDashboardVisualisationOptions\n\nexport interface ListDashboardVisualisationOptions {\n showLatest?: boolean\n columnsAsList?: boolean\n}\n\nexport interface BucketDashboardVisualisationOptions {\n useRagColour?: boolean\n buckets?: DashboardVisualisationBucket[]\n baseColour?: string\n}\n\nexport interface DashboardVisualisationBucket {\n min?: number | undefined\n max?: number | undefined\n hexColour?: string | undefined\n}\n\nexport type VisualisationDefinitionType = z.infer<typeof DashboardVisualisationSchemas.DashboardVisualisationSchema>\nexport type VisualisationDefinitionKey = z.infer<typeof DashboardVisualisationSchemas.DashboardVisualisationKeySchema>\nexport type VisualisationDefinitionMeasure = z.infer<\n typeof DashboardVisualisationSchemas.DashboardVisualisationMeasureSchema\n>\n\nexport type ChartMeasure =\n | BarDefinitionMeasure[]\n | DoughnutDefinitionMeasure[]\n | LineDefinitionMeasure[]\n | VisualisationDefinitionMeasure[]\n\nexport type TimeseriesChartMeasure = LineTimeseriesDefinitionMeasure[] | BarTimeseriesDefinitionMeasure[]\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import z from 'zod'\nimport { components } from '../../../types/api'\nimport { Scorecard, ScorecardGroup } from '../scorecard/types'\nimport { MatrixChartData } from '../../_charts/chart/heatmap/types'\nimport { ChartDetails } from '../../../types/Charts'\nimport DashboardVisualisationSchemas from './Validate'\nimport { BarDefinitionMeasure } from '../../_charts/chart/bar/types'\nimport { DoughnutDefinitionMeasure } from '../../_charts/chart/doughnut/types'\nimport { LineDefinitionMeasure } from '../../_charts/chart/line/types'\nimport { LineTimeseriesDefinitionMeasure } from '../../_charts/chart/line-timeseries/types'\nimport { BarTimeseriesDefinitionMeasure } from '../../_charts/chart/bar-timeseries/types'\nimport { ChartOptionsType } from '../../_charts/chart/chart-config'\nimport { PartialDate } from '../../_filters/types'\n\nexport interface DashboardSection {\n id: string\n title?: string\n description?: string\n visualisations?: DashboardVisualisation[]\n}\n\nexport interface DashboardVisualisation {\n id: string\n type: components['schemas']['DashboardVisualisationDefinition']['type']\n title?: string | undefined\n description?: string | undefined\n isEnabled: boolean\n data:\n | Scorecard\n | Scorecard[]\n | ScorecardGroup[]\n | DashboardVisualisatonCardData\n | DashboardVisualisationTable\n | undefined\n}\n\nexport interface DashboardVisualisatonCardData {\n chart?: DashboardVisualisationData | undefined\n table?: MoJTable | undefined\n details?: ChartDetails | undefined\n}\n\nexport interface DashboardVisualisationData {\n type: DashboardVisualisationType\n options?: DashboardVisualisationDataOptions\n data: DashboardVisualisationDataValues\n}\n\ninterface DashboardVisualisationDataOptions {\n height?: number\n unit?: components['schemas']['DashboardVisualisationColumnDefinition']['unit']\n timeseries?: boolean\n}\n\nexport interface DashboardVisualisationDataValues {\n labels?: string[]\n datasets: DashboardVisualisationDataSet[]\n axis?: 'x' | 'y'\n config: ChartOptionsType\n partialDate?: PartialDate | undefined\n}\n\nexport interface DashboardVisualisationDataSet {\n label: string\n data: number[] | MatrixChartData[]\n total?: number\n}\n\nexport interface DashboardVisualisationTable {\n table: MoJTable\n ts?: string\n}\n\nexport interface MoJTable {\n head: MoJTableHead[]\n rows: MoJTableRow[][]\n}\n\nexport interface MoJTableRow {\n text?: string\n html?: string\n}\n\nexport interface MoJTableHead {\n text?: string\n html?: string\n}\n\nexport enum DashboardVisualisationType {\n LIST = 'list',\n DONUT = 'doughnut',\n BAR = 'bar',\n LINE = 'line',\n MATRIX = 'matrix',\n MATRIX_TIMESERIES = 'matrix-timeseries',\n BAR_TIMESERIES = 'bar-timeseries',\n LINE_TIMESERIES = 'line-timeseries',\n SCORECARD = 'scorecard',\n SCORECARD_GROUP = 'scorecard-group',\n}\n\nexport type DashboardVisualisationOptions = ListDashboardVisualisationOptions | BucketDashboardVisualisationOptions\n\nexport interface ListDashboardVisualisationOptions {\n showLatest?: boolean\n columnsAsList?: boolean\n}\n\nexport interface BucketDashboardVisualisationOptions {\n useRagColour?: boolean\n buckets?: DashboardVisualisationBucket[]\n baseColour?: string\n}\n\nexport interface DashboardVisualisationBucket {\n min?: number | undefined\n max?: number | undefined\n hexColour?: string | undefined\n}\n\nexport type VisualisationDefinitionType = z.infer<typeof DashboardVisualisationSchemas.DashboardVisualisationSchema>\nexport type VisualisationDefinitionKey = z.infer<typeof DashboardVisualisationSchemas.DashboardVisualisationKeySchema>\nexport type VisualisationDefinitionMeasure = z.infer<\n typeof DashboardVisualisationSchemas.DashboardVisualisationMeasureSchema\n>\n\nexport type ChartMeasure =\n | BarDefinitionMeasure[]\n | DoughnutDefinitionMeasure[]\n | LineDefinitionMeasure[]\n | VisualisationDefinitionMeasure[]\n\nexport type TimeseriesChartMeasure = LineTimeseriesDefinitionMeasure[] | BarTimeseriesDefinitionMeasure[]\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwFO,IAAK,6BAAL,kBAAKA,gCAAL;AACL,EAAAA,4BAAA,UAAO;AACP,EAAAA,4BAAA,WAAQ;AACR,EAAAA,4BAAA,SAAM;AACN,EAAAA,4BAAA,UAAO;AACP,EAAAA,4BAAA,YAAS;AACT,EAAAA,4BAAA,uBAAoB;AACpB,EAAAA,4BAAA,oBAAiB;AACjB,EAAAA,4BAAA,qBAAkB;AAClB,EAAAA,4BAAA,eAAY;AACZ,EAAAA,4BAAA,qBAAkB;AAVR,SAAAA;AAAA,GAAA;",
|
|
6
6
|
"names": ["DashboardVisualisationType"]
|
|
7
7
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
{% set title = visualisation.title %}
|
|
9
9
|
{% set description = visualisation.description %}
|
|
10
10
|
{% set data = visualisation.data %}
|
|
11
|
+
{% set isEnabled = visualisation.isEnabled %}
|
|
11
12
|
|
|
12
13
|
<div class="dashboard-visualisation-container" id="{{ id }}-dash-section-visualisation" tabindex="0">
|
|
13
14
|
{% if title %}
|
|
@@ -18,18 +19,22 @@
|
|
|
18
19
|
<p class="govuk-body">{{ description }}</p>
|
|
19
20
|
{% endif %}
|
|
20
21
|
|
|
21
|
-
{% if
|
|
22
|
+
{% if not isEnabled %}
|
|
23
|
+
<p class="govuk-body">This visualisation type is not supported yet.</p>
|
|
24
|
+
{% else %}
|
|
25
|
+
{% if type === 'scorecard-group' %}
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
{{ dprScoreCardGroup(id, data) }}
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
{% elif type === 'list' %}
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
{{ dprDashboardList(id, data) }}
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
{% else %}
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
{{ dprChartCard(id, data) }}
|
|
36
|
+
|
|
37
|
+
{% endif %}
|
|
33
38
|
{% endif %}
|
|
34
39
|
|
|
35
40
|
</div>
|
|
@@ -23,7 +23,7 @@ __export(utils_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(utils_exports);
|
|
25
25
|
var import_types = require("../dashboard-visualisation/types");
|
|
26
|
-
const mergeScorecardsIntoGroup = (visualisations) => {
|
|
26
|
+
const mergeScorecardsIntoGroup = (visualisations, isEnabled) => {
|
|
27
27
|
const groupedScorecardIndexes = visualisations.reduce((acc, vis, i) => {
|
|
28
28
|
if (vis.type === import_types.DashboardVisualisationType.SCORECARD) acc.push(i);
|
|
29
29
|
return acc;
|
|
@@ -46,7 +46,8 @@ const mergeScorecardsIntoGroup = (visualisations) => {
|
|
|
46
46
|
visualisations.splice(spliceAtIndex, 0, {
|
|
47
47
|
id: `${spliceAtIndex}`,
|
|
48
48
|
type: import_types.DashboardVisualisationType.SCORECARD_GROUP,
|
|
49
|
-
data: [{ scorecards: scorecardGroup }]
|
|
49
|
+
data: [{ scorecards: scorecardGroup }],
|
|
50
|
+
isEnabled
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../dpr/components/_dashboards/scorecard/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { DashboardVisualisation, DashboardVisualisationType } from '../dashboard-visualisation/types'\nimport { Scorecard } from './types'\n\nexport const mergeScorecardsIntoGroup = (visualisations: DashboardVisualisation[]) => {\n const groupedScorecardIndexes: number[][] = visualisations\n // get scorecard indexes\n .reduce((acc: number[], vis: DashboardVisualisation, i: number) => {\n if (vis.type === DashboardVisualisationType.SCORECARD) acc.push(i)\n return acc\n }, [])\n // group adjacent indexes\n .reduce((r: number[][], n) => {\n const lastSubArray = r[r.length - 1]\n if (!lastSubArray || lastSubArray[lastSubArray.length - 1] !== n - 1) r.push([])\n r[r.length - 1].push(n)\n return r\n }, [])\n\n groupedScorecardIndexes.reverse().forEach((group: number[]) => {\n const spliceAtIndex = group[0]\n const scorecardGroup: Scorecard[] = group\n .map((scIndex: number) => {\n return visualisations[scIndex].data as Scorecard\n })\n .filter((scorecard: Scorecard) => !!scorecard)\n\n while (group.length) {\n const i = group.pop()\n if (i !== undefined) visualisations.splice(i, 1)\n }\n\n if (scorecardGroup.length) {\n visualisations.splice(spliceAtIndex, 0, {\n id: `${spliceAtIndex}`,\n type: DashboardVisualisationType.SCORECARD_GROUP,\n data: [{ scorecards: scorecardGroup }],\n })\n }\n })\n\n return visualisations\n}\n\nexport default {\n mergeScorecardsIntoGroup,\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAmE;AAG5D,MAAM,2BAA2B,CAAC,
|
|
4
|
+
"sourcesContent": ["import { DashboardVisualisation, DashboardVisualisationType } from '../dashboard-visualisation/types'\nimport { Scorecard } from './types'\n\nexport const mergeScorecardsIntoGroup = (visualisations: DashboardVisualisation[], isEnabled: boolean) => {\n const groupedScorecardIndexes: number[][] = visualisations\n // get scorecard indexes\n .reduce((acc: number[], vis: DashboardVisualisation, i: number) => {\n if (vis.type === DashboardVisualisationType.SCORECARD) acc.push(i)\n return acc\n }, [])\n // group adjacent indexes\n .reduce((r: number[][], n) => {\n const lastSubArray = r[r.length - 1]\n if (!lastSubArray || lastSubArray[lastSubArray.length - 1] !== n - 1) r.push([])\n r[r.length - 1].push(n)\n return r\n }, [])\n\n groupedScorecardIndexes.reverse().forEach((group: number[]) => {\n const spliceAtIndex = group[0]\n const scorecardGroup: Scorecard[] = group\n .map((scIndex: number) => {\n return visualisations[scIndex].data as Scorecard\n })\n .filter((scorecard: Scorecard) => !!scorecard)\n\n while (group.length) {\n const i = group.pop()\n if (i !== undefined) visualisations.splice(i, 1)\n }\n\n if (scorecardGroup.length) {\n visualisations.splice(spliceAtIndex, 0, {\n id: `${spliceAtIndex}`,\n type: DashboardVisualisationType.SCORECARD_GROUP,\n data: [{ scorecards: scorecardGroup }],\n isEnabled,\n })\n }\n })\n\n return visualisations\n}\n\nexport default {\n mergeScorecardsIntoGroup,\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAmE;AAG5D,MAAM,2BAA2B,CAAC,gBAA0C,cAAuB;AACxG,QAAM,0BAAsC,eAEzC,OAAO,CAAC,KAAe,KAA6B,MAAc;AACjE,QAAI,IAAI,SAAS,wCAA2B,UAAW,KAAI,KAAK,CAAC;AACjE,WAAO;AAAA,EACT,GAAG,CAAC,CAAC,EAEJ,OAAO,CAAC,GAAe,MAAM;AAC5B,UAAM,eAAe,EAAE,EAAE,SAAS,CAAC;AACnC,QAAI,CAAC,gBAAgB,aAAa,aAAa,SAAS,CAAC,MAAM,IAAI,EAAG,GAAE,KAAK,CAAC,CAAC;AAC/E,MAAE,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC;AACtB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEP,0BAAwB,QAAQ,EAAE,QAAQ,CAAC,UAAoB;AAC7D,UAAM,gBAAgB,MAAM,CAAC;AAC7B,UAAM,iBAA8B,MACjC,IAAI,CAAC,YAAoB;AACxB,aAAO,eAAe,OAAO,EAAE;AAAA,IACjC,CAAC,EACA,OAAO,CAAC,cAAyB,CAAC,CAAC,SAAS;AAE/C,WAAO,MAAM,QAAQ;AACnB,YAAM,IAAI,MAAM,IAAI;AACpB,UAAI,MAAM,OAAW,gBAAe,OAAO,GAAG,CAAC;AAAA,IACjD;AAEA,QAAI,eAAe,QAAQ;AACzB,qBAAe,OAAO,eAAe,GAAG;AAAA,QACtC,IAAI,GAAG,aAAa;AAAA,QACpB,MAAM,wCAA2B;AAAA,QACjC,MAAM,CAAC,EAAE,YAAY,eAAe,CAAC;AAAA,QACrC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,IAAO,gBAAQ;AAAA,EACb;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -53,33 +53,39 @@ describe('ScorecardUtils', () => {
|
|
|
53
53
|
id: '1',
|
|
54
54
|
type: DashboardVisualisationType.SCORECARD,
|
|
55
55
|
data: scorecardData1,
|
|
56
|
+
isEnabled: true,
|
|
56
57
|
},
|
|
57
58
|
{
|
|
58
59
|
id: '2',
|
|
59
60
|
type: DashboardVisualisationType.SCORECARD,
|
|
60
61
|
data: scorecardData2,
|
|
62
|
+
isEnabled: true,
|
|
61
63
|
},
|
|
62
64
|
{
|
|
63
65
|
id: '3',
|
|
64
66
|
type: DashboardVisualisationType.BAR,
|
|
65
67
|
data: {} as unknown as DashboardVisualisatonCardData,
|
|
68
|
+
isEnabled: true,
|
|
66
69
|
},
|
|
67
70
|
{
|
|
68
71
|
id: '4',
|
|
69
72
|
type: DashboardVisualisationType.SCORECARD,
|
|
70
73
|
data: scorecardData1,
|
|
74
|
+
isEnabled: true,
|
|
71
75
|
},
|
|
72
76
|
{
|
|
73
77
|
id: '5',
|
|
74
78
|
type: DashboardVisualisationType.SCORECARD,
|
|
75
79
|
data: scorecardData2,
|
|
80
|
+
isEnabled: true,
|
|
76
81
|
},
|
|
77
82
|
]
|
|
78
83
|
|
|
79
|
-
const dashboardVis = ScorecardUtils.mergeScorecardsIntoGroup(visualistationData)
|
|
84
|
+
const dashboardVis = ScorecardUtils.mergeScorecardsIntoGroup(visualistationData, true)
|
|
80
85
|
expect(dashboardVis).toEqual([
|
|
81
86
|
{
|
|
82
87
|
id: '0',
|
|
88
|
+
isEnabled: true,
|
|
83
89
|
type: 'scorecard-group',
|
|
84
90
|
data: [
|
|
85
91
|
{
|
|
@@ -120,11 +126,13 @@ describe('ScorecardUtils', () => {
|
|
|
120
126
|
},
|
|
121
127
|
{
|
|
122
128
|
id: '3',
|
|
129
|
+
isEnabled: true,
|
|
123
130
|
type: 'bar',
|
|
124
131
|
data: {},
|
|
125
132
|
},
|
|
126
133
|
{
|
|
127
134
|
id: '3',
|
|
135
|
+
isEnabled: true,
|
|
128
136
|
type: 'scorecard-group',
|
|
129
137
|
data: [
|
|
130
138
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DashboardVisualisation, DashboardVisualisationType } from '../dashboard-visualisation/types'
|
|
2
2
|
import { Scorecard } from './types'
|
|
3
3
|
|
|
4
|
-
export const mergeScorecardsIntoGroup = (visualisations: DashboardVisualisation[]) => {
|
|
4
|
+
export const mergeScorecardsIntoGroup = (visualisations: DashboardVisualisation[], isEnabled: boolean) => {
|
|
5
5
|
const groupedScorecardIndexes: number[][] = visualisations
|
|
6
6
|
// get scorecard indexes
|
|
7
7
|
.reduce((acc: number[], vis: DashboardVisualisation, i: number) => {
|
|
@@ -34,6 +34,7 @@ export const mergeScorecardsIntoGroup = (visualisations: DashboardVisualisation[
|
|
|
34
34
|
id: `${spliceAtIndex}`,
|
|
35
35
|
type: DashboardVisualisationType.SCORECARD_GROUP,
|
|
36
36
|
data: [{ scorecards: scorecardGroup }],
|
|
37
|
+
isEnabled,
|
|
37
38
|
})
|
|
38
39
|
}
|
|
39
40
|
})
|
|
@@ -34,6 +34,7 @@ __export(utils_exports, {
|
|
|
34
34
|
renderBookmarkList: () => renderBookmarkList
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(utils_exports);
|
|
37
|
+
var import_node = require("@sentry/node");
|
|
37
38
|
var import_UserReports = require("../../../types/UserReports");
|
|
38
39
|
var import_utils = __toESM(require("../../show-more/utils"));
|
|
39
40
|
var import_logger = __toESM(require("../../../utils/logger"));
|
|
@@ -143,6 +144,7 @@ const mapBookmarkIdsToDefinition = async (bookmarks, res, token, services) => {
|
|
|
143
144
|
});
|
|
144
145
|
}
|
|
145
146
|
} catch (error) {
|
|
147
|
+
(0, import_node.captureException)(error);
|
|
146
148
|
import_logger.default.warn(`Failed to map bookmark for: Report ${reportId}, variant ${id}`);
|
|
147
149
|
const { dprUser } = import_localsHelper.default.getValues(res);
|
|
148
150
|
await services.bookmarkService.removeBookmark(dprUser.id, id, reportId);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../dpr/components/user-reports/bookmarks/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { Response } from 'express'\nimport { BookmarkService } from '../../../services'\nimport { BookmarkedReportData, BookmarkStoreData } from '../../../types/Bookmark'\nimport { FormattedBookmarkData, LoadType, ReportType } from '../../../types/UserReports'\nimport { Services } from '../../../types/Services'\nimport ShowMoreUtils from '../../show-more/utils'\nimport logger from '../../../utils/logger'\nimport DefinitionUtils from '../../../utils/definitionUtils'\nimport { createListItemProduct, createListActions, setInitialHref } from '../../../utils/reportListsHelper'\nimport LocalsHelper from '../../../utils/localsHelper'\nimport { ReportStoreConfig } from '../../../types/ReportStore'\n\nexport const formatBookmarks = async (bookmarksData: BookmarkedReportData[]): Promise<FormattedBookmarkData[]> => {\n return bookmarksData\n .map((report: BookmarkedReportData) => {\n return formatBookmark(report)\n })\n .sort((a, b) => a.text.localeCompare(b.text))\n}\n\nexport const formatBookmark = (bookmarkData: BookmarkedReportData): FormattedBookmarkData => {\n const reportData: BookmarkedReportData = JSON.parse(JSON.stringify(bookmarkData))\n const { id, name, description, href, reportName, type } = reportData\n\n return {\n id,\n reportName,\n text: name,\n description,\n href,\n type: type as ReportType,\n }\n}\n\nconst formatTable = async (\n bookmarksData: BookmarkedReportData[],\n bookmarkService: BookmarkService,\n csrfToken: string,\n userId: string,\n maxRows?: number,\n nestedBaseUrl?: string,\n) => {\n const userConfig = await bookmarkService.getState(userId)\n const rows = await Promise.all(\n bookmarksData\n .sort((a, b) => a.name.localeCompare(b.name))\n .map(async (bookmark: BookmarkedReportData) => {\n return formatTableData(bookmark, bookmarkService, csrfToken, userConfig, nestedBaseUrl)\n }),\n )\n\n return {\n rows: maxRows ? rows.slice(0, maxRows) : rows,\n head: [\n { text: 'Product', classes: 'dpr-req-product-head' },\n { text: 'Description', classes: 'dpr-bm-description-head' },\n { text: 'Actions', classes: 'dpr-bm-actions-head' },\n ],\n }\n}\n\nconst formatTableData = async (\n bookmarksData: BookmarkedReportData,\n bookmarkService: BookmarkService,\n csrfToken: string,\n userConfig: ReportStoreConfig,\n nestedBaseUrl?: string,\n) => {\n const { description, reportName, reportId, id, href, name, type, loadType } = bookmarksData\n const bookmarkHtml = await bookmarkService.createBookMarkToggleHtml({\n userConfig,\n reportId,\n id,\n csrfToken,\n ctxId: 'bookmark-list',\n reportType: type,\n // We don't have the data here, and missing reports should never get into bookmarked, viewed or requested\n isMissing: false,\n nestedBaseUrl,\n })\n return [\n {\n html: createListItemProduct(reportName, name, type),\n },\n { html: ShowMoreUtils.createShowMoreHtml(description), classes: 'dpr-req-cell' },\n {\n html: createListActions(href, type, loadType, bookmarkHtml),\n classes: 'dpr-req-cell dpr-req-cell__status',\n },\n ]\n}\n\nconst mapBookmarkIdsToDefinition = async (\n bookmarks: BookmarkStoreData[],\n res: Response,\n token: string,\n services: Services,\n): Promise<BookmarkedReportData[]> => {\n const bookmarkData: BookmarkedReportData[] = []\n const { definitionsPath } = LocalsHelper.getValues(res)\n\n await Promise.all(\n bookmarks.map(async (bookmark) => {\n let definition\n const { reportId, id, automatic, type } = bookmark\n const reportType: ReportType = type ? (type as ReportType) : ReportType.REPORT\n\n try {\n let name = ''\n let description = ''\n let loadType = LoadType.ASYNC\n const href = setInitialHref(loadType, reportType, reportId, id, res)\n\n const procuctSummary = await DefinitionUtils.getReportSummary(\n reportId,\n services.reportingService,\n token,\n definitionsPath,\n )\n const reportName = procuctSummary.name\n\n if (reportType === ReportType.REPORT) {\n const variantSummary = procuctSummary.variants.find((v) => v.id === id)\n definition = await services.reportingService.getDefinition(token, reportId, id, definitionsPath)\n name = definition.variant.name\n description = definition.variant.description || definition.description || ''\n loadType = (variantSummary?.loadType as LoadType) || loadType\n }\n\n if (reportType === ReportType.DASHBOARD) {\n definition = await services.dashboardService.getDefinition(token, reportId, id, definitionsPath)\n name = definition.name\n description = definition.description || ''\n }\n\n if (definition) {\n bookmarkData.push({\n reportId,\n id,\n reportName,\n name,\n description,\n type: reportType,\n href,\n loadType,\n automatic,\n })\n }\n } catch (error) {\n // DPD has been deleted so API throws error\n logger.warn(`Failed to map bookmark for: Report ${reportId}, variant ${id}`)\n const { dprUser } = LocalsHelper.getValues(res)\n await services.bookmarkService.removeBookmark(dprUser.id, id, reportId)\n }\n }),\n )\n return bookmarkData\n}\n\nexport const renderBookmarkList = async ({\n services,\n maxRows = 20,\n res,\n}: {\n services: Services\n maxRows?: number\n res: Response\n}) => {\n const { token, csrfToken, dprUser, bookmarks, nestedBaseUrl } = LocalsHelper.getValues(res)\n const bookmarksData: BookmarkedReportData[] = await mapBookmarkIdsToDefinition(bookmarks, res, token, services)\n\n let formatted = await formatBookmarks(bookmarksData)\n const formattedCount = formatted.length\n\n if (maxRows) formatted = formatted.slice(0, maxRows)\n const tableData = await formatTable(\n bookmarksData,\n services.bookmarkService,\n csrfToken,\n dprUser.id,\n maxRows,\n nestedBaseUrl,\n )\n\n const head = {\n ...(formatted.length && { href: '/dpr/my-reports/bookmarks/list' }),\n ...(!formatted.length && { emptyMessage: 'You have 0 bookmarked reports' }),\n }\n\n const total = {\n amount: formattedCount,\n shown: formattedCount > maxRows ? maxRows : formattedCount,\n max: maxRows,\n }\n\n const result = {\n head,\n tableData,\n total,\n csrfToken,\n type: 'bookmark',\n }\n\n return result\n}\n\nexport default {\n renderBookmarkList,\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { Response } from 'express'\nimport { captureException } from '@sentry/node'\nimport { BookmarkService } from '../../../services'\nimport { BookmarkedReportData, BookmarkStoreData } from '../../../types/Bookmark'\nimport { FormattedBookmarkData, LoadType, ReportType } from '../../../types/UserReports'\nimport { Services } from '../../../types/Services'\nimport ShowMoreUtils from '../../show-more/utils'\nimport logger from '../../../utils/logger'\nimport DefinitionUtils from '../../../utils/definitionUtils'\nimport { createListItemProduct, createListActions, setInitialHref } from '../../../utils/reportListsHelper'\nimport LocalsHelper from '../../../utils/localsHelper'\nimport { ReportStoreConfig } from '../../../types/ReportStore'\n\nexport const formatBookmarks = async (bookmarksData: BookmarkedReportData[]): Promise<FormattedBookmarkData[]> => {\n return bookmarksData\n .map((report: BookmarkedReportData) => {\n return formatBookmark(report)\n })\n .sort((a, b) => a.text.localeCompare(b.text))\n}\n\nexport const formatBookmark = (bookmarkData: BookmarkedReportData): FormattedBookmarkData => {\n const reportData: BookmarkedReportData = JSON.parse(JSON.stringify(bookmarkData))\n const { id, name, description, href, reportName, type } = reportData\n\n return {\n id,\n reportName,\n text: name,\n description,\n href,\n type: type as ReportType,\n }\n}\n\nconst formatTable = async (\n bookmarksData: BookmarkedReportData[],\n bookmarkService: BookmarkService,\n csrfToken: string,\n userId: string,\n maxRows?: number,\n nestedBaseUrl?: string,\n) => {\n const userConfig = await bookmarkService.getState(userId)\n const rows = await Promise.all(\n bookmarksData\n .sort((a, b) => a.name.localeCompare(b.name))\n .map(async (bookmark: BookmarkedReportData) => {\n return formatTableData(bookmark, bookmarkService, csrfToken, userConfig, nestedBaseUrl)\n }),\n )\n\n return {\n rows: maxRows ? rows.slice(0, maxRows) : rows,\n head: [\n { text: 'Product', classes: 'dpr-req-product-head' },\n { text: 'Description', classes: 'dpr-bm-description-head' },\n { text: 'Actions', classes: 'dpr-bm-actions-head' },\n ],\n }\n}\n\nconst formatTableData = async (\n bookmarksData: BookmarkedReportData,\n bookmarkService: BookmarkService,\n csrfToken: string,\n userConfig: ReportStoreConfig,\n nestedBaseUrl?: string,\n) => {\n const { description, reportName, reportId, id, href, name, type, loadType } = bookmarksData\n const bookmarkHtml = await bookmarkService.createBookMarkToggleHtml({\n userConfig,\n reportId,\n id,\n csrfToken,\n ctxId: 'bookmark-list',\n reportType: type,\n // We don't have the data here, and missing reports should never get into bookmarked, viewed or requested\n isMissing: false,\n nestedBaseUrl,\n })\n return [\n {\n html: createListItemProduct(reportName, name, type),\n },\n { html: ShowMoreUtils.createShowMoreHtml(description), classes: 'dpr-req-cell' },\n {\n html: createListActions(href, type, loadType, bookmarkHtml),\n classes: 'dpr-req-cell dpr-req-cell__status',\n },\n ]\n}\n\nconst mapBookmarkIdsToDefinition = async (\n bookmarks: BookmarkStoreData[],\n res: Response,\n token: string,\n services: Services,\n): Promise<BookmarkedReportData[]> => {\n const bookmarkData: BookmarkedReportData[] = []\n const { definitionsPath } = LocalsHelper.getValues(res)\n\n await Promise.all(\n bookmarks.map(async (bookmark) => {\n let definition\n const { reportId, id, automatic, type } = bookmark\n const reportType: ReportType = type ? (type as ReportType) : ReportType.REPORT\n\n try {\n let name = ''\n let description = ''\n let loadType = LoadType.ASYNC\n const href = setInitialHref(loadType, reportType, reportId, id, res)\n\n const procuctSummary = await DefinitionUtils.getReportSummary(\n reportId,\n services.reportingService,\n token,\n definitionsPath,\n )\n const reportName = procuctSummary.name\n\n if (reportType === ReportType.REPORT) {\n const variantSummary = procuctSummary.variants.find((v) => v.id === id)\n definition = await services.reportingService.getDefinition(token, reportId, id, definitionsPath)\n name = definition.variant.name\n description = definition.variant.description || definition.description || ''\n loadType = (variantSummary?.loadType as LoadType) || loadType\n }\n\n if (reportType === ReportType.DASHBOARD) {\n definition = await services.dashboardService.getDefinition(token, reportId, id, definitionsPath)\n name = definition.name\n description = definition.description || ''\n }\n\n if (definition) {\n bookmarkData.push({\n reportId,\n id,\n reportName,\n name,\n description,\n type: reportType,\n href,\n loadType,\n automatic,\n })\n }\n } catch (error) {\n captureException(error)\n // DPD has been deleted so API throws error\n logger.warn(`Failed to map bookmark for: Report ${reportId}, variant ${id}`)\n const { dprUser } = LocalsHelper.getValues(res)\n await services.bookmarkService.removeBookmark(dprUser.id, id, reportId)\n }\n }),\n )\n return bookmarkData\n}\n\nexport const renderBookmarkList = async ({\n services,\n maxRows = 20,\n res,\n}: {\n services: Services\n maxRows?: number\n res: Response\n}) => {\n const { token, csrfToken, dprUser, bookmarks, nestedBaseUrl } = LocalsHelper.getValues(res)\n const bookmarksData: BookmarkedReportData[] = await mapBookmarkIdsToDefinition(bookmarks, res, token, services)\n\n let formatted = await formatBookmarks(bookmarksData)\n const formattedCount = formatted.length\n\n if (maxRows) formatted = formatted.slice(0, maxRows)\n const tableData = await formatTable(\n bookmarksData,\n services.bookmarkService,\n csrfToken,\n dprUser.id,\n maxRows,\n nestedBaseUrl,\n )\n\n const head = {\n ...(formatted.length && { href: '/dpr/my-reports/bookmarks/list' }),\n ...(!formatted.length && { emptyMessage: 'You have 0 bookmarked reports' }),\n }\n\n const total = {\n amount: formattedCount,\n shown: formattedCount > maxRows ? maxRows : formattedCount,\n max: maxRows,\n }\n\n const result = {\n head,\n tableData,\n total,\n csrfToken,\n type: 'bookmark',\n }\n\n return result\n}\n\nexport default {\n renderBookmarkList,\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["ShowMoreUtils", "LocalsHelper", "DefinitionUtils", "logger"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Response } from 'express'
|
|
2
|
+
import { captureException } from '@sentry/node'
|
|
2
3
|
import { BookmarkService } from '../../../services'
|
|
3
4
|
import { BookmarkedReportData, BookmarkStoreData } from '../../../types/Bookmark'
|
|
4
5
|
import { FormattedBookmarkData, LoadType, ReportType } from '../../../types/UserReports'
|
|
@@ -147,6 +148,7 @@ const mapBookmarkIdsToDefinition = async (
|
|
|
147
148
|
})
|
|
148
149
|
}
|
|
149
150
|
} catch (error) {
|
|
151
|
+
captureException(error)
|
|
150
152
|
// DPD has been deleted so API throws error
|
|
151
153
|
logger.warn(`Failed to map bookmark for: Report ${reportId}, variant ${id}`)
|
|
152
154
|
const { dprUser } = LocalsHelper.getValues(res)
|
package/dpr/data/types.d.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../dpr/data/types.d.ts"],
|
|
4
|
-
"sourcesContent": ["import AgentConfig from './agentConfig'\nimport Dict = NodeJS.Dict\n\nexport interface GetRequest {\n path?: string\n query?: object\n headers?: Record<string, string>\n responseType?: string\n raw?: boolean\n token: string\n}\n\nexport interface FeatureFlagConfig {\n
|
|
4
|
+
"sourcesContent": ["import AgentConfig from './agentConfig'\nimport Dict = NodeJS.Dict\n\nexport interface GetRequest {\n path?: string\n query?: object\n headers?: Record<string, string>\n responseType?: string\n raw?: boolean\n token: string\n}\n\nexport interface FeatureFlagConfig {\n token: string\n url: string\n}\n\nexport interface ApiConfig {\n url: string\n agent: AgentConfig\n}\n\nexport interface Count {\n count: number\n}\n\nexport interface ListWithWarnings {\n data: Array<Dict<string>>\n warnings: Warnings\n}\n\nexport interface Warnings {\n noDataAvailable?: string | undefined\n}\n\nexport interface FieldValuesRequest {\n token: string\n definitionName: string\n variantName: string\n fieldName: string\n prefix: string\n definitionsPath?: string\n}\n\nexport interface AsyncRequestQuery {\n sortColumn: string\n sortedAsc: boolean\n dataProductDefinitionsPath: string\n [key: string]: string | boolean\n}\n\ninterface filter {\n [filterId: string]: string\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dpr/data/types.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ __export(controller_exports, {
|
|
|
32
32
|
default: () => controller_default
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(controller_exports);
|
|
35
|
+
var import_node = require("@sentry/node");
|
|
35
36
|
var import_utils = __toESM(require("./utils"));
|
|
36
37
|
var import_utils2 = __toESM(require("../../../../components/user-reports/requested/utils"));
|
|
37
38
|
var import_ErrorHandler = __toESM(require("../../../../utils/ErrorHandler"));
|
|
@@ -69,6 +70,7 @@ class RequestStatusController {
|
|
|
69
70
|
const response = await import_utils2.default.getRequestStatus({ req, res, services: this.services });
|
|
70
71
|
res.send({ status: response.status });
|
|
71
72
|
} catch (error) {
|
|
73
|
+
(0, import_node.captureException)(error);
|
|
72
74
|
res.send({ status: "FAILED" });
|
|
73
75
|
}
|
|
74
76
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../dpr/routes/journeys/request-report/status/controller.ts"],
|
|
4
|
-
"sourcesContent": ["import { RequestHandler } from 'express'\nimport { Services } from '../../../../types/Services'\nimport AsyncPollingUtils from './utils'\nimport AsyncRequestListUtils from '../../../../components/user-reports/requested/utils'\nimport ErrorHandler from '../../../../utils/ErrorHandler'\n\nclass RequestStatusController {\n layoutPath: string\n\n services: Services\n\n constructor(layoutPath: string, services: Services) {\n this.layoutPath = layoutPath\n this.services = services\n }\n\n // Render status page\n GET: RequestHandler = async (req, res, next) => {\n try {\n const pollingRenderData = await AsyncPollingUtils.renderPolling({\n req,\n res,\n services: this.services,\n next,\n })\n res.render(`dpr/routes/journeys/request-report/status/view`, {\n layoutPath: this.layoutPath,\n ...pollingRenderData,\n })\n } catch (error) {\n req.body ??= {}\n req.body.title = 'Failed to retrieve report status'\n req.body.errorDescription = 'We were unable to retrieve the report status:'\n req.body.error = new ErrorHandler(error).formatError()\n next(error)\n }\n }\n\n // Poll request status\n POST: RequestHandler = async (req, res, _next) => {\n try {\n const response = await AsyncRequestListUtils.getRequestStatus({ req, res, services: this.services })\n res.send({ status: response.status })\n } catch (error) {\n res.send({ status: 'FAILED' })\n }\n }\n}\n\nexport { RequestStatusController }\nexport default RequestStatusController\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { RequestHandler } from 'express'\nimport { captureException } from '@sentry/node'\nimport { Services } from '../../../../types/Services'\nimport AsyncPollingUtils from './utils'\nimport AsyncRequestListUtils from '../../../../components/user-reports/requested/utils'\nimport ErrorHandler from '../../../../utils/ErrorHandler'\n\nclass RequestStatusController {\n layoutPath: string\n\n services: Services\n\n constructor(layoutPath: string, services: Services) {\n this.layoutPath = layoutPath\n this.services = services\n }\n\n // Render status page\n GET: RequestHandler = async (req, res, next) => {\n try {\n const pollingRenderData = await AsyncPollingUtils.renderPolling({\n req,\n res,\n services: this.services,\n next,\n })\n res.render(`dpr/routes/journeys/request-report/status/view`, {\n layoutPath: this.layoutPath,\n ...pollingRenderData,\n })\n } catch (error) {\n req.body ??= {}\n req.body.title = 'Failed to retrieve report status'\n req.body.errorDescription = 'We were unable to retrieve the report status:'\n req.body.error = new ErrorHandler(error).formatError()\n next(error)\n }\n }\n\n // Poll request status\n POST: RequestHandler = async (req, res, _next) => {\n try {\n const response = await AsyncRequestListUtils.getRequestStatus({ req, res, services: this.services })\n res.send({ status: response.status })\n } catch (error) {\n captureException(error)\n res.send({ status: 'FAILED' })\n }\n }\n}\n\nexport { RequestStatusController }\nexport default RequestStatusController\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAiC;AAEjC,mBAA8B;AAC9B,IAAAA,gBAAkC;AAClC,0BAAyB;AAEzB,MAAM,wBAAwB;AAAA,EAC5B;AAAA,EAEA;AAAA,EAEA,YAAY,YAAoB,UAAoB;AAClD,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAsB,OAAO,KAAK,KAAK,SAAS;AAC9C,QAAI;AACF,YAAM,oBAAoB,MAAM,aAAAC,QAAkB,cAAc;AAAA,QAC9D;AAAA,QACA;AAAA,QACA,UAAU,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AACD,UAAI,OAAO,kDAAkD;AAAA,QAC3D,YAAY,KAAK;AAAA,QACjB,GAAG;AAAA,MACL,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,SAAS,CAAC;AACd,UAAI,KAAK,QAAQ;AACjB,UAAI,KAAK,mBAAmB;AAC5B,UAAI,KAAK,QAAQ,IAAI,oBAAAC,QAAa,KAAK,EAAE,YAAY;AACrD,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA;AAAA,EAGA,OAAuB,OAAO,KAAK,KAAK,UAAU;AAChD,QAAI;AACF,YAAM,WAAW,MAAM,cAAAC,QAAsB,iBAAiB,EAAE,KAAK,KAAK,UAAU,KAAK,SAAS,CAAC;AACnG,UAAI,KAAK,EAAE,QAAQ,SAAS,OAAO,CAAC;AAAA,IACtC,SAAS,OAAO;AACd,wCAAiB,KAAK;AACtB,UAAI,KAAK,EAAE,QAAQ,SAAS,CAAC;AAAA,IAC/B;AAAA,EACF;AACF;AAGA,IAAO,qBAAQ;",
|
|
6
6
|
"names": ["import_utils", "AsyncPollingUtils", "ErrorHandler", "AsyncRequestListUtils"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RequestHandler } from 'express'
|
|
2
|
+
import { captureException } from '@sentry/node'
|
|
2
3
|
import { Services } from '../../../../types/Services'
|
|
3
4
|
import AsyncPollingUtils from './utils'
|
|
4
5
|
import AsyncRequestListUtils from '../../../../components/user-reports/requested/utils'
|
|
@@ -42,6 +43,7 @@ class RequestStatusController {
|
|
|
42
43
|
const response = await AsyncRequestListUtils.getRequestStatus({ req, res, services: this.services })
|
|
43
44
|
res.send({ status: response.status })
|
|
44
45
|
} catch (error) {
|
|
46
|
+
captureException(error)
|
|
45
47
|
res.send({ status: 'FAILED' })
|
|
46
48
|
}
|
|
47
49
|
}
|
|
@@ -32,6 +32,7 @@ __export(controller_exports, {
|
|
|
32
32
|
default: () => controller_default
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(controller_exports);
|
|
35
|
+
var import_node = require("@sentry/node");
|
|
35
36
|
var import_ErrorHandler = __toESM(require("../../../../utils/ErrorHandler"));
|
|
36
37
|
var import_utils = __toESM(require("../../../../components/user-reports/utils"));
|
|
37
38
|
var import_filtersTypeEnum = require("../../../../components/_filters/filtersTypeEnum");
|
|
@@ -52,6 +53,7 @@ class AsyncController {
|
|
|
52
53
|
});
|
|
53
54
|
res.send({ isExpired: response });
|
|
54
55
|
} catch (error) {
|
|
56
|
+
(0, import_node.captureException)(error);
|
|
55
57
|
res.send({ status: "FAILED" });
|
|
56
58
|
}
|
|
57
59
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../dpr/routes/journeys/view-report/async/controller.ts"],
|
|
4
|
-
"sourcesContent": ["import { RequestHandler } from 'express'\nimport ErrorHandler from '../../../../utils/ErrorHandler'\nimport { Services } from '../../../../types/Services'\nimport UserReportsListUtils from '../../../../components/user-reports/utils'\nimport { FiltersType } from '../../../../components/_filters/filtersTypeEnum'\nimport PersonalisationUtils from '../../../../utils/Personalisation/personalisationUtils'\n\nclass AsyncController {\n layoutPath: string\n\n services: Services\n\n constructor(layoutPath: string, services: Services) {\n this.layoutPath = layoutPath\n this.services = services\n }\n\n POST: RequestHandler = async (req, res, _next) => {\n try {\n const response = await UserReportsListUtils.updateExpiredStatus({\n req,\n res,\n services: this.services,\n })\n res.send({ isExpired: response })\n } catch (error) {\n res.send({ status: 'FAILED' })\n }\n }\n\n saveDefaultFilterValues: RequestHandler = async (req, res, next) => {\n try {\n PersonalisationUtils.saveDefaults(FiltersType.INTERACTIVE, res, req, this.services)\n res.redirect(`${req.baseUrl}?defaultsSaved=true`)\n } catch (error) {\n req.body = {\n title: 'Failed to save defaults',\n error: new ErrorHandler(error).formatError(),\n ...(req.body && { ...req.body }),\n }\n next(error)\n }\n }\n\n removeDefaultFilterValues: RequestHandler = async (req, res, next) => {\n try {\n PersonalisationUtils.removeDefaults(FiltersType.INTERACTIVE, res, req, this.services)\n res.redirect(req.baseUrl)\n } catch (error) {\n req.body = {\n title: 'Failed to remove defaults',\n error: new ErrorHandler(error).formatError(),\n ...(req.body && { ...req.body }),\n }\n next(error)\n }\n }\n}\n\nexport { AsyncController }\nexport default AsyncController\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAyB;AAEzB,mBAAiC;AACjC,6BAA4B;AAC5B,kCAAiC;AAEjC,MAAM,gBAAgB;AAAA,EACpB;AAAA,EAEA;AAAA,EAEA,YAAY,YAAoB,UAAoB;AAClD,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,OAAuB,OAAO,KAAK,KAAK,UAAU;AAChD,QAAI;AACF,YAAM,WAAW,MAAM,aAAAA,QAAqB,oBAAoB;AAAA,QAC9D;AAAA,QACA;AAAA,QACA,UAAU,KAAK;AAAA,MACjB,CAAC;AACD,UAAI,KAAK,EAAE,WAAW,SAAS,CAAC;AAAA,IAClC,SAAS,OAAO;AACd,UAAI,KAAK,EAAE,QAAQ,SAAS,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,0BAA0C,OAAO,KAAK,KAAK,SAAS;AAClE,QAAI;AACF,kCAAAC,QAAqB,aAAa,mCAAY,aAAa,KAAK,KAAK,KAAK,QAAQ;AAClF,UAAI,SAAS,GAAG,IAAI,OAAO,qBAAqB;AAAA,IAClD,SAAS,OAAO;AACd,UAAI,OAAO;AAAA,QACT,OAAO;AAAA,QACP,OAAO,IAAI,oBAAAC,QAAa,KAAK,EAAE,YAAY;AAAA,QAC3C,GAAI,IAAI,QAAQ,EAAE,GAAG,IAAI,KAAK;AAAA,MAChC;AACA,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,4BAA4C,OAAO,KAAK,KAAK,SAAS;AACpE,QAAI;AACF,kCAAAD,QAAqB,eAAe,mCAAY,aAAa,KAAK,KAAK,KAAK,QAAQ;AACpF,UAAI,SAAS,IAAI,OAAO;AAAA,IAC1B,SAAS,OAAO;AACd,UAAI,OAAO;AAAA,QACT,OAAO;AAAA,QACP,OAAO,IAAI,oBAAAC,QAAa,KAAK,EAAE,YAAY;AAAA,QAC3C,GAAI,IAAI,QAAQ,EAAE,GAAG,IAAI,KAAK;AAAA,MAChC;AACA,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AACF;AAGA,IAAO,qBAAQ;",
|
|
4
|
+
"sourcesContent": ["import { RequestHandler } from 'express'\nimport { captureException } from '@sentry/node'\nimport ErrorHandler from '../../../../utils/ErrorHandler'\nimport { Services } from '../../../../types/Services'\nimport UserReportsListUtils from '../../../../components/user-reports/utils'\nimport { FiltersType } from '../../../../components/_filters/filtersTypeEnum'\nimport PersonalisationUtils from '../../../../utils/Personalisation/personalisationUtils'\n\nclass AsyncController {\n layoutPath: string\n\n services: Services\n\n constructor(layoutPath: string, services: Services) {\n this.layoutPath = layoutPath\n this.services = services\n }\n\n POST: RequestHandler = async (req, res, _next) => {\n try {\n const response = await UserReportsListUtils.updateExpiredStatus({\n req,\n res,\n services: this.services,\n })\n res.send({ isExpired: response })\n } catch (error) {\n captureException(error)\n res.send({ status: 'FAILED' })\n }\n }\n\n saveDefaultFilterValues: RequestHandler = async (req, res, next) => {\n try {\n PersonalisationUtils.saveDefaults(FiltersType.INTERACTIVE, res, req, this.services)\n res.redirect(`${req.baseUrl}?defaultsSaved=true`)\n } catch (error) {\n req.body = {\n title: 'Failed to save defaults',\n error: new ErrorHandler(error).formatError(),\n ...(req.body && { ...req.body }),\n }\n next(error)\n }\n }\n\n removeDefaultFilterValues: RequestHandler = async (req, res, next) => {\n try {\n PersonalisationUtils.removeDefaults(FiltersType.INTERACTIVE, res, req, this.services)\n res.redirect(req.baseUrl)\n } catch (error) {\n req.body = {\n title: 'Failed to remove defaults',\n error: new ErrorHandler(error).formatError(),\n ...(req.body && { ...req.body }),\n }\n next(error)\n }\n }\n}\n\nexport { AsyncController }\nexport default AsyncController\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAiC;AACjC,0BAAyB;AAEzB,mBAAiC;AACjC,6BAA4B;AAC5B,kCAAiC;AAEjC,MAAM,gBAAgB;AAAA,EACpB;AAAA,EAEA;AAAA,EAEA,YAAY,YAAoB,UAAoB;AAClD,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,OAAuB,OAAO,KAAK,KAAK,UAAU;AAChD,QAAI;AACF,YAAM,WAAW,MAAM,aAAAA,QAAqB,oBAAoB;AAAA,QAC9D;AAAA,QACA;AAAA,QACA,UAAU,KAAK;AAAA,MACjB,CAAC;AACD,UAAI,KAAK,EAAE,WAAW,SAAS,CAAC;AAAA,IAClC,SAAS,OAAO;AACd,wCAAiB,KAAK;AACtB,UAAI,KAAK,EAAE,QAAQ,SAAS,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,0BAA0C,OAAO,KAAK,KAAK,SAAS;AAClE,QAAI;AACF,kCAAAC,QAAqB,aAAa,mCAAY,aAAa,KAAK,KAAK,KAAK,QAAQ;AAClF,UAAI,SAAS,GAAG,IAAI,OAAO,qBAAqB;AAAA,IAClD,SAAS,OAAO;AACd,UAAI,OAAO;AAAA,QACT,OAAO;AAAA,QACP,OAAO,IAAI,oBAAAC,QAAa,KAAK,EAAE,YAAY;AAAA,QAC3C,GAAI,IAAI,QAAQ,EAAE,GAAG,IAAI,KAAK;AAAA,MAChC;AACA,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,4BAA4C,OAAO,KAAK,KAAK,SAAS;AACpE,QAAI;AACF,kCAAAD,QAAqB,eAAe,mCAAY,aAAa,KAAK,KAAK,KAAK,QAAQ;AACpF,UAAI,SAAS,IAAI,OAAO;AAAA,IAC1B,SAAS,OAAO;AACd,UAAI,OAAO;AAAA,QACT,OAAO;AAAA,QACP,OAAO,IAAI,oBAAAC,QAAa,KAAK,EAAE,YAAY;AAAA,QAC3C,GAAI,IAAI,QAAQ,EAAE,GAAG,IAAI,KAAK;AAAA,MAChC;AACA,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AACF;AAGA,IAAO,qBAAQ;",
|
|
6
6
|
"names": ["UserReportsListUtils", "PersonalisationUtils", "ErrorHandler"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RequestHandler } from 'express'
|
|
2
|
+
import { captureException } from '@sentry/node'
|
|
2
3
|
import ErrorHandler from '../../../../utils/ErrorHandler'
|
|
3
4
|
import { Services } from '../../../../types/Services'
|
|
4
5
|
import UserReportsListUtils from '../../../../components/user-reports/utils'
|
|
@@ -24,6 +25,7 @@ class AsyncController {
|
|
|
24
25
|
})
|
|
25
26
|
res.send({ isExpired: response })
|
|
26
27
|
} catch (error) {
|
|
28
|
+
captureException(error)
|
|
27
29
|
res.send({ status: 'FAILED' })
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var import_appStateUtils = require("test-app/routes/integrationTests/appStateUtils");
|
|
2
3
|
var import_cypressUtils = require("../../../../../../../cypress-tests/cypressUtils");
|
|
3
4
|
context("Viewing a report", () => {
|
|
4
5
|
const path = "/embedded/platform/";
|
|
@@ -8,7 +9,9 @@ context("Viewing a report", () => {
|
|
|
8
9
|
cy.task("stubTestDashboard8");
|
|
9
10
|
cy.task("stubDashboardSuccessResult20");
|
|
10
11
|
});
|
|
11
|
-
it("should mark the dashboard as recently viewed", () => {
|
|
12
|
+
it("should mark the dashboard as recently viewed and not show viz", () => {
|
|
13
|
+
cy.task("stubFeatureFlagsDisabled");
|
|
14
|
+
(0, import_appStateUtils.resetFeatureFlags)();
|
|
12
15
|
cy.visit(path);
|
|
13
16
|
cy.findByRole("tab", { name: /Viewed \(0\)/ }).should("be.visible");
|
|
14
17
|
(0, import_cypressUtils.checkA11y)();
|
|
@@ -26,9 +29,32 @@ context("Viewing a report", () => {
|
|
|
26
29
|
(0, import_cypressUtils.checkA11y)();
|
|
27
30
|
cy.findByRole("heading", { level: 1, name: /Test Dashboard/ }).should("be.visible");
|
|
28
31
|
(0, import_cypressUtils.checkA11y)();
|
|
32
|
+
cy.findAllByText(/This visualisation type is not supported yet./).each((el) => cy.wrap(el).should("be.visible")).should("have.length.at.least", 1);
|
|
33
|
+
cy.get("canvas").should("not.exist");
|
|
29
34
|
cy.visit(path);
|
|
30
35
|
cy.findByRole("tab", { name: /Viewed \(1\)/ }).should("be.visible");
|
|
31
36
|
});
|
|
37
|
+
it("should show viz", () => {
|
|
38
|
+
cy.task("stubFeatureFlags");
|
|
39
|
+
(0, import_appStateUtils.resetFeatureFlags)();
|
|
40
|
+
cy.visit(path);
|
|
41
|
+
cy.findByLabelText(/Reports catalogue.*/i).within(() => {
|
|
42
|
+
cy.findByRole("row", {
|
|
43
|
+
name: (_, element) => {
|
|
44
|
+
return Boolean(element.textContent?.includes("Test Dashboard")) && Boolean(element.textContent?.includes("Dashboard used for testing testing"));
|
|
45
|
+
}
|
|
46
|
+
}).within(() => {
|
|
47
|
+
cy.findByRole("link", { name: "Request dashboard" }).click();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
(0, import_cypressUtils.checkA11y)();
|
|
51
|
+
cy.findByRole("button", { name: /Request/ }).click();
|
|
52
|
+
(0, import_cypressUtils.checkA11y)();
|
|
53
|
+
cy.findByRole("heading", { level: 1, name: /Test Dashboard/ }).should("be.visible");
|
|
54
|
+
(0, import_cypressUtils.checkA11y)();
|
|
55
|
+
cy.findAllByText(/This visualisation type is not supported yet./).should("have.length", 0);
|
|
56
|
+
cy.get("canvas").should("have.length.at.least", 1);
|
|
57
|
+
});
|
|
32
58
|
});
|
|
33
59
|
});
|
|
34
60
|
//# sourceMappingURL=tests.cy.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../dpr/routes/journeys/view-report/async/dashboard/tests.cy.ts"],
|
|
4
|
-
"sourcesContent": ["import { checkA11y, executeDashboardStubs } from '../../../../../../../cypress-tests/cypressUtils'\n\ncontext('Viewing a report', () => {\n const path = '/embedded/platform/'\n\n describe('dashboard tests', () => {\n before(() => {\n executeDashboardStubs()\n cy.task('stubTestDashboard8')\n cy.task('stubDashboardSuccessResult20')\n })\n\n it('should mark the dashboard as recently viewed', () => {\n // Request and run a report so we can go back to it for each test\n cy.visit(path)\n cy.findByRole('tab', { name: /Viewed \\(0\\)/ }).should('be.visible')\n checkA11y()\n cy.findByLabelText(/Reports catalogue.*/i).within(() => {\n cy.findByRole('row', {\n name: (_, element) => {\n return (\n Boolean(element.textContent?.includes('Test Dashboard')) &&\n Boolean(element.textContent?.includes('Dashboard used for testing testing'))\n )\n },\n }).within(() => {\n cy.findByRole('link', { name: 'Request dashboard' }).click()\n })\n })\n checkA11y()\n cy.findByRole('button', { name: /Request/ }).click()\n checkA11y()\n cy.findByRole('heading', { level: 1, name: /Test Dashboard/ }).should('be.visible')\n checkA11y()\n cy.visit(path)\n cy.findByRole('tab', { name: /Viewed \\(1\\)/ }).should('be.visible')\n })\n })\n})\n"],
|
|
5
|
-
"mappings": ";AAAA,0BAAiD;AAEjD,QAAQ,oBAAoB,MAAM;AAChC,QAAM,OAAO;AAEb,WAAS,mBAAmB,MAAM;AAChC,WAAO,MAAM;AACX,qDAAsB;AACtB,SAAG,KAAK,oBAAoB;AAC5B,SAAG,KAAK,8BAA8B;AAAA,IACxC,CAAC;AAED,OAAG,
|
|
4
|
+
"sourcesContent": ["import { resetFeatureFlags } from 'test-app/routes/integrationTests/appStateUtils'\nimport { checkA11y, executeDashboardStubs } from '../../../../../../../cypress-tests/cypressUtils'\n\ncontext('Viewing a report', () => {\n const path = '/embedded/platform/'\n\n describe('dashboard tests', () => {\n before(() => {\n executeDashboardStubs()\n cy.task('stubTestDashboard8')\n cy.task('stubDashboardSuccessResult20')\n })\n\n it('should mark the dashboard as recently viewed and not show viz', () => {\n cy.task('stubFeatureFlagsDisabled')\n resetFeatureFlags()\n // Request and run a report so we can go back to it for each test\n cy.visit(path)\n cy.findByRole('tab', { name: /Viewed \\(0\\)/ }).should('be.visible')\n checkA11y()\n cy.findByLabelText(/Reports catalogue.*/i).within(() => {\n cy.findByRole('row', {\n name: (_, element) => {\n return (\n Boolean(element.textContent?.includes('Test Dashboard')) &&\n Boolean(element.textContent?.includes('Dashboard used for testing testing'))\n )\n },\n }).within(() => {\n cy.findByRole('link', { name: 'Request dashboard' }).click()\n })\n })\n checkA11y()\n cy.findByRole('button', { name: /Request/ }).click()\n checkA11y()\n cy.findByRole('heading', { level: 1, name: /Test Dashboard/ }).should('be.visible')\n checkA11y()\n cy.findAllByText(/This visualisation type is not supported yet./)\n .each((el) => cy.wrap(el).should('be.visible'))\n .should('have.length.at.least', 1)\n cy.get('canvas').should('not.exist')\n cy.visit(path)\n cy.findByRole('tab', { name: /Viewed \\(1\\)/ }).should('be.visible')\n })\n\n it('should show viz', () => {\n cy.task('stubFeatureFlags')\n resetFeatureFlags()\n // Request and run a report so we can go back to it for each test\n cy.visit(path)\n cy.findByLabelText(/Reports catalogue.*/i).within(() => {\n cy.findByRole('row', {\n name: (_, element) => {\n return (\n Boolean(element.textContent?.includes('Test Dashboard')) &&\n Boolean(element.textContent?.includes('Dashboard used for testing testing'))\n )\n },\n }).within(() => {\n cy.findByRole('link', { name: 'Request dashboard' }).click()\n })\n })\n checkA11y()\n cy.findByRole('button', { name: /Request/ }).click()\n checkA11y()\n cy.findByRole('heading', { level: 1, name: /Test Dashboard/ }).should('be.visible')\n checkA11y()\n cy.findAllByText(/This visualisation type is not supported yet./).should('have.length', 0)\n cy.get('canvas').should('have.length.at.least', 1)\n })\n })\n})\n"],
|
|
5
|
+
"mappings": ";AAAA,2BAAkC;AAClC,0BAAiD;AAEjD,QAAQ,oBAAoB,MAAM;AAChC,QAAM,OAAO;AAEb,WAAS,mBAAmB,MAAM;AAChC,WAAO,MAAM;AACX,qDAAsB;AACtB,SAAG,KAAK,oBAAoB;AAC5B,SAAG,KAAK,8BAA8B;AAAA,IACxC,CAAC;AAED,OAAG,iEAAiE,MAAM;AACxE,SAAG,KAAK,0BAA0B;AAClC,kDAAkB;AAElB,SAAG,MAAM,IAAI;AACb,SAAG,WAAW,OAAO,EAAE,MAAM,eAAe,CAAC,EAAE,OAAO,YAAY;AAClE,yCAAU;AACV,SAAG,gBAAgB,sBAAsB,EAAE,OAAO,MAAM;AACtD,WAAG,WAAW,OAAO;AAAA,UACnB,MAAM,CAAC,GAAG,YAAY;AACpB,mBACE,QAAQ,QAAQ,aAAa,SAAS,gBAAgB,CAAC,KACvD,QAAQ,QAAQ,aAAa,SAAS,oCAAoC,CAAC;AAAA,UAE/E;AAAA,QACF,CAAC,EAAE,OAAO,MAAM;AACd,aAAG,WAAW,QAAQ,EAAE,MAAM,oBAAoB,CAAC,EAAE,MAAM;AAAA,QAC7D,CAAC;AAAA,MACH,CAAC;AACD,yCAAU;AACV,SAAG,WAAW,UAAU,EAAE,MAAM,UAAU,CAAC,EAAE,MAAM;AACnD,yCAAU;AACV,SAAG,WAAW,WAAW,EAAE,OAAO,GAAG,MAAM,iBAAiB,CAAC,EAAE,OAAO,YAAY;AAClF,yCAAU;AACV,SAAG,cAAc,+CAA+C,EAC7D,KAAK,CAAC,OAAO,GAAG,KAAK,EAAE,EAAE,OAAO,YAAY,CAAC,EAC7C,OAAO,wBAAwB,CAAC;AACnC,SAAG,IAAI,QAAQ,EAAE,OAAO,WAAW;AACnC,SAAG,MAAM,IAAI;AACb,SAAG,WAAW,OAAO,EAAE,MAAM,eAAe,CAAC,EAAE,OAAO,YAAY;AAAA,IACpE,CAAC;AAED,OAAG,mBAAmB,MAAM;AAC1B,SAAG,KAAK,kBAAkB;AAC1B,kDAAkB;AAElB,SAAG,MAAM,IAAI;AACb,SAAG,gBAAgB,sBAAsB,EAAE,OAAO,MAAM;AACtD,WAAG,WAAW,OAAO;AAAA,UACnB,MAAM,CAAC,GAAG,YAAY;AACpB,mBACE,QAAQ,QAAQ,aAAa,SAAS,gBAAgB,CAAC,KACvD,QAAQ,QAAQ,aAAa,SAAS,oCAAoC,CAAC;AAAA,UAE/E;AAAA,QACF,CAAC,EAAE,OAAO,MAAM;AACd,aAAG,WAAW,QAAQ,EAAE,MAAM,oBAAoB,CAAC,EAAE,MAAM;AAAA,QAC7D,CAAC;AAAA,MACH,CAAC;AACD,yCAAU;AACV,SAAG,WAAW,UAAU,EAAE,MAAM,UAAU,CAAC,EAAE,MAAM;AACnD,yCAAU;AACV,SAAG,WAAW,WAAW,EAAE,OAAO,GAAG,MAAM,iBAAiB,CAAC,EAAE,OAAO,YAAY;AAClF,yCAAU;AACV,SAAG,cAAc,+CAA+C,EAAE,OAAO,eAAe,CAAC;AACzF,SAAG,IAAI,QAAQ,EAAE,OAAO,wBAAwB,CAAC;AAAA,IACnD,CAAC;AAAA,EACH,CAAC;AACH,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resetFeatureFlags } from 'test-app/routes/integrationTests/appStateUtils'
|
|
1
2
|
import { checkA11y, executeDashboardStubs } from '../../../../../../../cypress-tests/cypressUtils'
|
|
2
3
|
|
|
3
4
|
context('Viewing a report', () => {
|
|
@@ -10,7 +11,9 @@ context('Viewing a report', () => {
|
|
|
10
11
|
cy.task('stubDashboardSuccessResult20')
|
|
11
12
|
})
|
|
12
13
|
|
|
13
|
-
it('should mark the dashboard as recently viewed', () => {
|
|
14
|
+
it('should mark the dashboard as recently viewed and not show viz', () => {
|
|
15
|
+
cy.task('stubFeatureFlagsDisabled')
|
|
16
|
+
resetFeatureFlags()
|
|
14
17
|
// Request and run a report so we can go back to it for each test
|
|
15
18
|
cy.visit(path)
|
|
16
19
|
cy.findByRole('tab', { name: /Viewed \(0\)/ }).should('be.visible')
|
|
@@ -32,8 +35,38 @@ context('Viewing a report', () => {
|
|
|
32
35
|
checkA11y()
|
|
33
36
|
cy.findByRole('heading', { level: 1, name: /Test Dashboard/ }).should('be.visible')
|
|
34
37
|
checkA11y()
|
|
38
|
+
cy.findAllByText(/This visualisation type is not supported yet./)
|
|
39
|
+
.each((el) => cy.wrap(el).should('be.visible'))
|
|
40
|
+
.should('have.length.at.least', 1)
|
|
41
|
+
cy.get('canvas').should('not.exist')
|
|
35
42
|
cy.visit(path)
|
|
36
43
|
cy.findByRole('tab', { name: /Viewed \(1\)/ }).should('be.visible')
|
|
37
44
|
})
|
|
45
|
+
|
|
46
|
+
it('should show viz', () => {
|
|
47
|
+
cy.task('stubFeatureFlags')
|
|
48
|
+
resetFeatureFlags()
|
|
49
|
+
// Request and run a report so we can go back to it for each test
|
|
50
|
+
cy.visit(path)
|
|
51
|
+
cy.findByLabelText(/Reports catalogue.*/i).within(() => {
|
|
52
|
+
cy.findByRole('row', {
|
|
53
|
+
name: (_, element) => {
|
|
54
|
+
return (
|
|
55
|
+
Boolean(element.textContent?.includes('Test Dashboard')) &&
|
|
56
|
+
Boolean(element.textContent?.includes('Dashboard used for testing testing'))
|
|
57
|
+
)
|
|
58
|
+
},
|
|
59
|
+
}).within(() => {
|
|
60
|
+
cy.findByRole('link', { name: 'Request dashboard' }).click()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
checkA11y()
|
|
64
|
+
cy.findByRole('button', { name: /Request/ }).click()
|
|
65
|
+
checkA11y()
|
|
66
|
+
cy.findByRole('heading', { level: 1, name: /Test Dashboard/ }).should('be.visible')
|
|
67
|
+
checkA11y()
|
|
68
|
+
cy.findAllByText(/This visualisation type is not supported yet./).should('have.length', 0)
|
|
69
|
+
cy.get('canvas').should('have.length.at.least', 1)
|
|
70
|
+
})
|
|
38
71
|
})
|
|
39
72
|
})
|
|
@@ -117,13 +117,41 @@ const getDefinitionData = async ({
|
|
|
117
117
|
reportDefinition
|
|
118
118
|
};
|
|
119
119
|
};
|
|
120
|
-
const getSections = (dashboardDefinition, dashboardData, query, partialDate) => {
|
|
120
|
+
const getSections = (dashboardDefinition, dashboardData, query, dashboardFeatureFlags, partialDate) => {
|
|
121
121
|
return dashboardDefinition.sections.map((section) => {
|
|
122
122
|
const { id, display: title, description } = section;
|
|
123
|
+
const featureFlagVisTypeMap = {
|
|
124
|
+
[import_types.DashboardVisualisationType.LIST]: true,
|
|
125
|
+
[import_types.DashboardVisualisationType.BAR]: Boolean(
|
|
126
|
+
dashboardFeatureFlags.find((flag) => flag.key === "barChartsEnabled" && flag.enabled)
|
|
127
|
+
),
|
|
128
|
+
[import_types.DashboardVisualisationType.LINE]: Boolean(
|
|
129
|
+
dashboardFeatureFlags.find((flag) => flag.key === "lineChartsEnabled" && flag.enabled)
|
|
130
|
+
),
|
|
131
|
+
[import_types.DashboardVisualisationType.DONUT]: Boolean(
|
|
132
|
+
dashboardFeatureFlags.find((flag) => flag.key === "donutChartsEnabled" && flag.enabled)
|
|
133
|
+
),
|
|
134
|
+
[import_types.DashboardVisualisationType.SCORECARD]: Boolean(
|
|
135
|
+
dashboardFeatureFlags.find((flag) => flag.key === "scorecardChartsEnabled" && flag.enabled)
|
|
136
|
+
),
|
|
137
|
+
[import_types.DashboardVisualisationType.SCORECARD_GROUP]: Boolean(
|
|
138
|
+
dashboardFeatureFlags.find((flag) => flag.key === "scorecardgroupChartsEnabled" && flag.enabled)
|
|
139
|
+
),
|
|
140
|
+
[import_types.DashboardVisualisationType.MATRIX_TIMESERIES]: Boolean(
|
|
141
|
+
dashboardFeatureFlags.find((flag) => flag.key === "matrixtimeseriesChartsEnabled" && flag.enabled)
|
|
142
|
+
),
|
|
143
|
+
[import_types.DashboardVisualisationType.BAR_TIMESERIES]: Boolean(
|
|
144
|
+
dashboardFeatureFlags.find((flag) => flag.key === "bartimeseriesChartsEnabled" && flag.enabled)
|
|
145
|
+
),
|
|
146
|
+
[import_types.DashboardVisualisationType.LINE_TIMESERIES]: Boolean(
|
|
147
|
+
dashboardFeatureFlags.find((flag) => flag.key === "linetimeseriesChartsEnabled" && flag.enabled)
|
|
148
|
+
)
|
|
149
|
+
};
|
|
123
150
|
let hasScorecard = false;
|
|
124
151
|
const visualisations = section.visualisations.map(
|
|
125
152
|
(visDefinition) => {
|
|
126
153
|
const { type, display, description: visDescription, id: visId } = visDefinition;
|
|
154
|
+
const isEnabled = featureFlagVisTypeMap[type];
|
|
127
155
|
let data;
|
|
128
156
|
switch (type) {
|
|
129
157
|
case import_types.DashboardVisualisationType.LIST:
|
|
@@ -156,11 +184,16 @@ const getSections = (dashboardDefinition, dashboardData, query, partialDate) =>
|
|
|
156
184
|
title: display || "",
|
|
157
185
|
description: visDescription || "",
|
|
158
186
|
type,
|
|
159
|
-
data
|
|
187
|
+
data,
|
|
188
|
+
isEnabled: isEnabled ?? true
|
|
160
189
|
};
|
|
161
190
|
}
|
|
162
191
|
);
|
|
163
|
-
if (hasScorecard)
|
|
192
|
+
if (hasScorecard)
|
|
193
|
+
import_utils5.default.mergeScorecardsIntoGroup(
|
|
194
|
+
visualisations,
|
|
195
|
+
featureFlagVisTypeMap[import_types.DashboardVisualisationType.SCORECARD_GROUP]
|
|
196
|
+
);
|
|
164
197
|
return { id, title: title || "", description: description || "", visualisations };
|
|
165
198
|
});
|
|
166
199
|
};
|
|
@@ -208,7 +241,16 @@ const renderAsyncDashboard = async ({ req, res, services }) => {
|
|
|
208
241
|
);
|
|
209
242
|
const flattenedData = dashboardData.flat();
|
|
210
243
|
const partialDate = getPartialDate(filters.filters);
|
|
211
|
-
const
|
|
244
|
+
const dashboardFeatureFlags = Object.values(res.app.locals.featureFlags.flags).filter(
|
|
245
|
+
(flag) => flag.metadata["dashboardFeature"] === true
|
|
246
|
+
);
|
|
247
|
+
const sections = getSections(
|
|
248
|
+
dashboardDefinition,
|
|
249
|
+
flattenedData,
|
|
250
|
+
query,
|
|
251
|
+
dashboardFeatureFlags,
|
|
252
|
+
partialDate
|
|
253
|
+
);
|
|
212
254
|
if (requestedReportService) {
|
|
213
255
|
requestData = await updateStore(services, tableId, dprUser.id, sections, req, filters.filters);
|
|
214
256
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../dpr/routes/journeys/view-report/async/dashboard/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { Request, Response } from 'express'\nimport { Services } from '../../../../../types/Services'\nimport Dict = NodeJS.Dict\nimport {\n DashboardSection,\n DashboardVisualisation,\n DashboardVisualisationType,\n} from '../../../../../components/_dashboards/dashboard-visualisation/types'\nimport type { AsyncReportUtilsParams } from '../../../../../types/AsyncReportUtils'\n\nimport type { DashboardDataResponse } from '../../../../../types/Metrics'\nimport type { RequestedReport } from '../../../../../types/UserReports'\nimport { ReportType } from '../../../../../types/UserReports'\nimport type { components } from '../../../../../types/api'\n\nimport ChartUtils from '../../../../../components/_charts/utils'\nimport DefinitionUtils from '../../../../../utils/definitionUtils'\nimport UserReportsUtils from '../../../../../components/user-reports/utils'\nimport DashboardListUtils from '../../../../../components/_dashboards/dashboard-list/utils'\nimport FilterUtils from '../../../../../components/_filters/utils'\nimport ScorecardsUtils from '../../../../../components/_dashboards/scorecard/utils'\nimport ScorecardVisualisation from '../../../../../components/_dashboards/scorecard/Scorecard'\nimport ScorecardGroupVisualisation from '../../../../../components/_dashboards/scorecard-group/ScorecardGroup'\nimport ReportActionsUtils from '../../../../../components/_reports/report-heading/report-actions/utils'\nimport ReportQuery from '../../../../../types/ReportQuery'\nimport LocalsHelper from '../../../../../utils/localsHelper'\nimport { FilterValue, GranularDateRangeFilterValue, PartialDate } from '../../../../../components/_filters/types'\nimport { FiltersType } from '../../../../../components/_filters/filtersTypeEnum'\nimport { FilterType } from '../../../../../components/_filters/filter-input/enum'\n\nconst setDashboardActions = (\n dashboardDefinition: components['schemas']['DashboardDefinition'],\n reportDefinition: components['schemas']['ReportDefinitionSummary'],\n requestData?: RequestedReport,\n) => {\n const reportName = reportDefinition.name\n const { name } = dashboardDefinition\n const actionsUrl = requestData?.url?.request?.fullUrl\n const executionId = requestData?.executionId\n\n let actions = {}\n if (actionsUrl) {\n actions = {\n share: {\n reportName,\n name,\n url: actionsUrl,\n },\n copy: {\n url: actionsUrl,\n },\n }\n if (executionId) {\n actions = {\n ...actions,\n refresh: {\n url: actionsUrl,\n executionId,\n },\n }\n }\n }\n\n return ReportActionsUtils.getActions(actions)\n}\n\nconst getDefinitionData = async ({\n req,\n res,\n services,\n queryData,\n}: {\n req: Request\n res: Response\n services: Services\n queryData?: Dict<string | string[]> | undefined\n}) => {\n const { token } = LocalsHelper.getValues(res)\n const { reportId, id } = req.params\n const dataProductDefinitionsPath = <string>req.query['dataProductDefinitionsPath']\n\n // Dashboard Definition,\n const dashboardDefinition = await services.dashboardService.getDefinition(\n token,\n reportId,\n id,\n dataProductDefinitionsPath,\n queryData,\n )\n\n // Report summary data\n const reportDefinition = await DefinitionUtils.getReportSummary(\n reportId,\n services.reportingService,\n token,\n <string>dataProductDefinitionsPath,\n )\n\n // Get the filters\n const filtersData = await FilterUtils.getFilters({\n fields: dashboardDefinition.filterFields || [],\n req,\n filtersType: FiltersType.INTERACTIVE,\n })\n\n const filtersQuery = FilterUtils.setRequestQueryFromFilterValues(filtersData.filters)\n\n // Create the query\n const query = new ReportQuery({\n fields: dashboardDefinition.filterFields || [],\n queryParams: filtersQuery,\n definitionsPath: <string>dataProductDefinitionsPath,\n reportType: ReportType.DASHBOARD,\n }).toRecordWithFilterPrefix(true)\n\n return {\n query,\n filters: filtersData,\n dashboardDefinition,\n reportDefinition,\n }\n}\n\nconst getSections = (\n dashboardDefinition: components['schemas']['DashboardDefinition'],\n dashboardData: DashboardDataResponse[],\n query: Record<string, string | string[]>,\n partialDate?: PartialDate,\n): DashboardSection[] => {\n return dashboardDefinition.sections.map((section: components['schemas']['DashboardSectionDefinition']) => {\n const { id, display: title, description } = section\n\n let hasScorecard = false\n const visualisations: DashboardVisualisation[] = section.visualisations.map(\n (visDefinition: components['schemas']['DashboardVisualisationDefinition']) => {\n const { type, display, description: visDescription, id: visId } = visDefinition\n\n let data: DashboardVisualisation['data'] | undefined\n\n switch (type) {\n case DashboardVisualisationType.LIST:\n data = DashboardListUtils.createList(visDefinition, dashboardData)\n break\n\n case DashboardVisualisationType.SCORECARD:\n hasScorecard = true\n data = new ScorecardVisualisation().withDefinition(visDefinition).withData(dashboardData).build()\n break\n\n case DashboardVisualisationType.SCORECARD_GROUP:\n data = new ScorecardGroupVisualisation().withDefinition(visDefinition).withData(dashboardData).build()\n break\n\n case DashboardVisualisationType.BAR:\n case DashboardVisualisationType.LINE:\n case DashboardVisualisationType.DONUT: {\n data = ChartUtils.createChart(visDefinition, dashboardData, type)\n break\n }\n case DashboardVisualisationType.MATRIX_TIMESERIES:\n case DashboardVisualisationType.BAR_TIMESERIES:\n case DashboardVisualisationType.LINE_TIMESERIES: {\n data = ChartUtils.createTimeseriesCharts(visDefinition, dashboardData, type, query, partialDate)\n break\n }\n default:\n break\n }\n\n return {\n id: visId,\n title: display || '',\n description: visDescription || '',\n type,\n data,\n }\n },\n )\n\n if (hasScorecard) ScorecardsUtils.mergeScorecardsIntoGroup(visualisations)\n\n return { id, title: title || '', description: description || '', visualisations }\n })\n}\n\nconst updateStore = async (\n services: Services,\n tableId: string,\n userId: string,\n sections: DashboardSection[],\n req: Request,\n filters: FilterValue[],\n): Promise<RequestedReport | undefined> => {\n const { requestedReportService } = services\n const dashboardRequestData = await requestedReportService.getReportByTableId(tableId, userId)\n\n // Add to recently viewed\n if (sections && sections.length && dashboardRequestData) {\n UserReportsUtils.updateLastViewed({\n services,\n reportStateData: dashboardRequestData,\n userId,\n req,\n filters,\n })\n }\n\n return dashboardRequestData\n}\n\nconst getPartialDate = (filters: FilterValue[]) => {\n let partialDate: PartialDate | undefined\n const granularDateRangeFilter = <GranularDateRangeFilterValue | undefined>(\n filters.find((f) => f.type === FilterType.granularDateRange.toLowerCase())\n )\n if (granularDateRangeFilter) {\n partialDate = granularDateRangeFilter.value.partialDate\n }\n return partialDate\n}\n\nexport const renderAsyncDashboard = async ({ req, res, services }: AsyncReportUtilsParams) => {\n const { token, csrfToken, dprUser, nestedBaseUrl } = LocalsHelper.getValues(res)\n const { reportId, id, tableId } = req.params\n const { bookmarkService, requestedReportService } = services\n const { id: userId } = dprUser\n\n let requestData: RequestedReport | undefined = await requestedReportService.getReportByTableId(tableId, userId)\n const queryData = requestData?.query?.data\n\n // Get the definition Data\n const { query, filters, reportDefinition, dashboardDefinition } = await getDefinitionData({\n req,\n res,\n services,\n queryData,\n })\n\n // Get the results data\n const dashboardData: DashboardDataResponse[][] = await services.dashboardService.getAsyncDashboard(\n token,\n id,\n reportId,\n tableId,\n query,\n )\n\n const flattenedData: DashboardDataResponse[] = dashboardData.flat()\n const partialDate = getPartialDate(filters.filters)\n\n // Get the dashboard parts\n const sections: DashboardSection[] = getSections(dashboardDefinition, flattenedData, query, partialDate)\n\n // Update the store\n if (requestedReportService) {\n requestData = await updateStore(services, tableId, dprUser.id, sections, req, filters.filters)\n }\n\n return {\n dashboardData: {\n token,\n id,\n reportId,\n name: dashboardDefinition.name,\n description: dashboardDefinition.description,\n reportName: reportDefinition.name,\n bookmarked: await bookmarkService.isBookmarked(id, reportId, dprUser.id),\n nestedBaseUrl,\n csrfToken,\n sections,\n filters,\n type: ReportType.DASHBOARD,\n actions: setDashboardActions(dashboardDefinition, reportDefinition, requestData),\n },\n }\n}\n\nexport default {\n renderAsyncDashboard,\n getDefinitionData,\n getSections,\n setDashboardActions,\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { Request, Response } from 'express'\nimport { Flag } from '@flipt-io/flipt'\nimport { Services } from '../../../../../types/Services'\nimport Dict = NodeJS.Dict\nimport {\n DashboardSection,\n DashboardVisualisation,\n DashboardVisualisationType,\n} from '../../../../../components/_dashboards/dashboard-visualisation/types'\nimport type { AsyncReportUtilsParams } from '../../../../../types/AsyncReportUtils'\n\nimport type { DashboardDataResponse } from '../../../../../types/Metrics'\nimport type { RequestedReport } from '../../../../../types/UserReports'\nimport { ReportType } from '../../../../../types/UserReports'\nimport type { components } from '../../../../../types/api'\n\nimport ChartUtils from '../../../../../components/_charts/utils'\nimport DefinitionUtils from '../../../../../utils/definitionUtils'\nimport UserReportsUtils from '../../../../../components/user-reports/utils'\nimport DashboardListUtils from '../../../../../components/_dashboards/dashboard-list/utils'\nimport FilterUtils from '../../../../../components/_filters/utils'\nimport ScorecardsUtils from '../../../../../components/_dashboards/scorecard/utils'\nimport ScorecardVisualisation from '../../../../../components/_dashboards/scorecard/Scorecard'\nimport ScorecardGroupVisualisation from '../../../../../components/_dashboards/scorecard-group/ScorecardGroup'\nimport ReportActionsUtils from '../../../../../components/_reports/report-heading/report-actions/utils'\nimport ReportQuery from '../../../../../types/ReportQuery'\nimport LocalsHelper from '../../../../../utils/localsHelper'\nimport { FilterValue, GranularDateRangeFilterValue, PartialDate } from '../../../../../components/_filters/types'\nimport { FiltersType } from '../../../../../components/_filters/filtersTypeEnum'\nimport { FilterType } from '../../../../../components/_filters/filter-input/enum'\n\nconst setDashboardActions = (\n dashboardDefinition: components['schemas']['DashboardDefinition'],\n reportDefinition: components['schemas']['ReportDefinitionSummary'],\n requestData?: RequestedReport,\n) => {\n const reportName = reportDefinition.name\n const { name } = dashboardDefinition\n const actionsUrl = requestData?.url?.request?.fullUrl\n const executionId = requestData?.executionId\n\n let actions = {}\n if (actionsUrl) {\n actions = {\n share: {\n reportName,\n name,\n url: actionsUrl,\n },\n copy: {\n url: actionsUrl,\n },\n }\n if (executionId) {\n actions = {\n ...actions,\n refresh: {\n url: actionsUrl,\n executionId,\n },\n }\n }\n }\n\n return ReportActionsUtils.getActions(actions)\n}\n\nconst getDefinitionData = async ({\n req,\n res,\n services,\n queryData,\n}: {\n req: Request\n res: Response\n services: Services\n queryData?: Dict<string | string[]> | undefined\n}) => {\n const { token } = LocalsHelper.getValues(res)\n const { reportId, id } = req.params\n const dataProductDefinitionsPath = <string>req.query['dataProductDefinitionsPath']\n\n // Dashboard Definition,\n const dashboardDefinition = await services.dashboardService.getDefinition(\n token,\n reportId,\n id,\n dataProductDefinitionsPath,\n queryData,\n )\n\n // Report summary data\n const reportDefinition = await DefinitionUtils.getReportSummary(\n reportId,\n services.reportingService,\n token,\n <string>dataProductDefinitionsPath,\n )\n\n // Get the filters\n const filtersData = await FilterUtils.getFilters({\n fields: dashboardDefinition.filterFields || [],\n req,\n filtersType: FiltersType.INTERACTIVE,\n })\n\n const filtersQuery = FilterUtils.setRequestQueryFromFilterValues(filtersData.filters)\n\n // Create the query\n const query = new ReportQuery({\n fields: dashboardDefinition.filterFields || [],\n queryParams: filtersQuery,\n definitionsPath: <string>dataProductDefinitionsPath,\n reportType: ReportType.DASHBOARD,\n }).toRecordWithFilterPrefix(true)\n\n return {\n query,\n filters: filtersData,\n dashboardDefinition,\n reportDefinition,\n }\n}\n\nconst getSections = (\n dashboardDefinition: components['schemas']['DashboardDefinition'],\n dashboardData: DashboardDataResponse[],\n query: Record<string, string | string[]>,\n dashboardFeatureFlags: Flag[],\n partialDate?: PartialDate,\n): DashboardSection[] => {\n return dashboardDefinition.sections.map((section: components['schemas']['DashboardSectionDefinition']) => {\n const { id, display: title, description } = section\n\n const featureFlagVisTypeMap = {\n [DashboardVisualisationType.LIST]: true,\n [DashboardVisualisationType.BAR]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'barChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.LINE]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'lineChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.DONUT]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'donutChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.SCORECARD]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'scorecardChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.SCORECARD_GROUP]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'scorecardgroupChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.MATRIX_TIMESERIES]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'matrixtimeseriesChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.BAR_TIMESERIES]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'bartimeseriesChartsEnabled' && flag.enabled),\n ),\n [DashboardVisualisationType.LINE_TIMESERIES]: Boolean(\n dashboardFeatureFlags.find((flag) => flag.key === 'linetimeseriesChartsEnabled' && flag.enabled),\n ),\n }\n\n let hasScorecard = false\n const visualisations: DashboardVisualisation[] = section.visualisations.map(\n (visDefinition: components['schemas']['DashboardVisualisationDefinition']) => {\n const { type, display, description: visDescription, id: visId } = visDefinition\n const isEnabled = featureFlagVisTypeMap[type]\n\n let data: DashboardVisualisation['data'] | undefined\n\n switch (type) {\n case DashboardVisualisationType.LIST:\n data = DashboardListUtils.createList(visDefinition, dashboardData)\n break\n\n case DashboardVisualisationType.SCORECARD:\n hasScorecard = true\n data = new ScorecardVisualisation().withDefinition(visDefinition).withData(dashboardData).build()\n break\n\n case DashboardVisualisationType.SCORECARD_GROUP:\n data = new ScorecardGroupVisualisation().withDefinition(visDefinition).withData(dashboardData).build()\n break\n\n case DashboardVisualisationType.BAR:\n case DashboardVisualisationType.LINE:\n case DashboardVisualisationType.DONUT: {\n data = ChartUtils.createChart(visDefinition, dashboardData, type)\n break\n }\n case DashboardVisualisationType.MATRIX_TIMESERIES:\n case DashboardVisualisationType.BAR_TIMESERIES:\n case DashboardVisualisationType.LINE_TIMESERIES: {\n data = ChartUtils.createTimeseriesCharts(visDefinition, dashboardData, type, query, partialDate)\n break\n }\n default:\n break\n }\n\n return {\n id: visId,\n title: display || '',\n description: visDescription || '',\n type,\n data,\n isEnabled: isEnabled ?? true,\n }\n },\n )\n\n if (hasScorecard)\n ScorecardsUtils.mergeScorecardsIntoGroup(\n visualisations,\n featureFlagVisTypeMap[DashboardVisualisationType.SCORECARD_GROUP],\n )\n\n return { id, title: title || '', description: description || '', visualisations }\n })\n}\n\nconst updateStore = async (\n services: Services,\n tableId: string,\n userId: string,\n sections: DashboardSection[],\n req: Request,\n filters: FilterValue[],\n): Promise<RequestedReport | undefined> => {\n const { requestedReportService } = services\n const dashboardRequestData = await requestedReportService.getReportByTableId(tableId, userId)\n\n // Add to recently viewed\n if (sections && sections.length && dashboardRequestData) {\n UserReportsUtils.updateLastViewed({\n services,\n reportStateData: dashboardRequestData,\n userId,\n req,\n filters,\n })\n }\n\n return dashboardRequestData\n}\n\nconst getPartialDate = (filters: FilterValue[]) => {\n let partialDate: PartialDate | undefined\n const granularDateRangeFilter = <GranularDateRangeFilterValue | undefined>(\n filters.find((f) => f.type === FilterType.granularDateRange.toLowerCase())\n )\n if (granularDateRangeFilter) {\n partialDate = granularDateRangeFilter.value.partialDate\n }\n return partialDate\n}\n\nexport const renderAsyncDashboard = async ({ req, res, services }: AsyncReportUtilsParams) => {\n const { token, csrfToken, dprUser, nestedBaseUrl } = LocalsHelper.getValues(res)\n const { reportId, id, tableId } = req.params\n const { bookmarkService, requestedReportService } = services\n const { id: userId } = dprUser\n\n let requestData: RequestedReport | undefined = await requestedReportService.getReportByTableId(tableId, userId)\n const queryData = requestData?.query?.data\n\n // Get the definition Data\n const { query, filters, reportDefinition, dashboardDefinition } = await getDefinitionData({\n req,\n res,\n services,\n queryData,\n })\n\n // Get the results data\n const dashboardData: DashboardDataResponse[][] = await services.dashboardService.getAsyncDashboard(\n token,\n id,\n reportId,\n tableId,\n query,\n )\n\n const flattenedData: DashboardDataResponse[] = dashboardData.flat()\n const partialDate = getPartialDate(filters.filters)\n\n // Get the dashboard parts\n const dashboardFeatureFlags = Object.values(res.app.locals.featureFlags.flags).filter(\n (flag) => flag.metadata['dashboardFeature'] === true,\n )\n const sections: DashboardSection[] = getSections(\n dashboardDefinition,\n flattenedData,\n query,\n dashboardFeatureFlags,\n partialDate,\n )\n\n // Update the store\n if (requestedReportService) {\n requestData = await updateStore(services, tableId, dprUser.id, sections, req, filters.filters)\n }\n\n return {\n dashboardData: {\n token,\n id,\n reportId,\n name: dashboardDefinition.name,\n description: dashboardDefinition.description,\n reportName: reportDefinition.name,\n bookmarked: await bookmarkService.isBookmarked(id, reportId, dprUser.id),\n nestedBaseUrl,\n csrfToken,\n sections,\n filters,\n type: ReportType.DASHBOARD,\n actions: setDashboardActions(dashboardDefinition, reportDefinition, requestData),\n },\n }\n}\n\nexport default {\n renderAsyncDashboard,\n getDefinitionData,\n getSections,\n setDashboardActions,\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_utils", "ReportActionsUtils", "LocalsHelper", "DefinitionUtils", "FilterUtils", "ReportQuery", "DashboardListUtils", "ScorecardVisualisation", "ScorecardGroupVisualisation", "ChartUtils", "ScorecardsUtils", "UserReportsUtils"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Request, Response } from 'express'
|
|
2
|
+
import { Flag } from '@flipt-io/flipt'
|
|
2
3
|
import { Services } from '../../../../../types/Services'
|
|
3
4
|
import Dict = NodeJS.Dict
|
|
4
5
|
import {
|
|
@@ -125,15 +126,45 @@ const getSections = (
|
|
|
125
126
|
dashboardDefinition: components['schemas']['DashboardDefinition'],
|
|
126
127
|
dashboardData: DashboardDataResponse[],
|
|
127
128
|
query: Record<string, string | string[]>,
|
|
129
|
+
dashboardFeatureFlags: Flag[],
|
|
128
130
|
partialDate?: PartialDate,
|
|
129
131
|
): DashboardSection[] => {
|
|
130
132
|
return dashboardDefinition.sections.map((section: components['schemas']['DashboardSectionDefinition']) => {
|
|
131
133
|
const { id, display: title, description } = section
|
|
132
134
|
|
|
135
|
+
const featureFlagVisTypeMap = {
|
|
136
|
+
[DashboardVisualisationType.LIST]: true,
|
|
137
|
+
[DashboardVisualisationType.BAR]: Boolean(
|
|
138
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'barChartsEnabled' && flag.enabled),
|
|
139
|
+
),
|
|
140
|
+
[DashboardVisualisationType.LINE]: Boolean(
|
|
141
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'lineChartsEnabled' && flag.enabled),
|
|
142
|
+
),
|
|
143
|
+
[DashboardVisualisationType.DONUT]: Boolean(
|
|
144
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'donutChartsEnabled' && flag.enabled),
|
|
145
|
+
),
|
|
146
|
+
[DashboardVisualisationType.SCORECARD]: Boolean(
|
|
147
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'scorecardChartsEnabled' && flag.enabled),
|
|
148
|
+
),
|
|
149
|
+
[DashboardVisualisationType.SCORECARD_GROUP]: Boolean(
|
|
150
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'scorecardgroupChartsEnabled' && flag.enabled),
|
|
151
|
+
),
|
|
152
|
+
[DashboardVisualisationType.MATRIX_TIMESERIES]: Boolean(
|
|
153
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'matrixtimeseriesChartsEnabled' && flag.enabled),
|
|
154
|
+
),
|
|
155
|
+
[DashboardVisualisationType.BAR_TIMESERIES]: Boolean(
|
|
156
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'bartimeseriesChartsEnabled' && flag.enabled),
|
|
157
|
+
),
|
|
158
|
+
[DashboardVisualisationType.LINE_TIMESERIES]: Boolean(
|
|
159
|
+
dashboardFeatureFlags.find((flag) => flag.key === 'linetimeseriesChartsEnabled' && flag.enabled),
|
|
160
|
+
),
|
|
161
|
+
}
|
|
162
|
+
|
|
133
163
|
let hasScorecard = false
|
|
134
164
|
const visualisations: DashboardVisualisation[] = section.visualisations.map(
|
|
135
165
|
(visDefinition: components['schemas']['DashboardVisualisationDefinition']) => {
|
|
136
166
|
const { type, display, description: visDescription, id: visId } = visDefinition
|
|
167
|
+
const isEnabled = featureFlagVisTypeMap[type]
|
|
137
168
|
|
|
138
169
|
let data: DashboardVisualisation['data'] | undefined
|
|
139
170
|
|
|
@@ -173,11 +204,16 @@ const getSections = (
|
|
|
173
204
|
description: visDescription || '',
|
|
174
205
|
type,
|
|
175
206
|
data,
|
|
207
|
+
isEnabled: isEnabled ?? true,
|
|
176
208
|
}
|
|
177
209
|
},
|
|
178
210
|
)
|
|
179
211
|
|
|
180
|
-
if (hasScorecard)
|
|
212
|
+
if (hasScorecard)
|
|
213
|
+
ScorecardsUtils.mergeScorecardsIntoGroup(
|
|
214
|
+
visualisations,
|
|
215
|
+
featureFlagVisTypeMap[DashboardVisualisationType.SCORECARD_GROUP],
|
|
216
|
+
)
|
|
181
217
|
|
|
182
218
|
return { id, title: title || '', description: description || '', visualisations }
|
|
183
219
|
})
|
|
@@ -249,7 +285,16 @@ export const renderAsyncDashboard = async ({ req, res, services }: AsyncReportUt
|
|
|
249
285
|
const partialDate = getPartialDate(filters.filters)
|
|
250
286
|
|
|
251
287
|
// Get the dashboard parts
|
|
252
|
-
const
|
|
288
|
+
const dashboardFeatureFlags = Object.values(res.app.locals.featureFlags.flags).filter(
|
|
289
|
+
(flag) => flag.metadata['dashboardFeature'] === true,
|
|
290
|
+
)
|
|
291
|
+
const sections: DashboardSection[] = getSections(
|
|
292
|
+
dashboardDefinition,
|
|
293
|
+
flattenedData,
|
|
294
|
+
query,
|
|
295
|
+
dashboardFeatureFlags,
|
|
296
|
+
partialDate,
|
|
297
|
+
)
|
|
253
298
|
|
|
254
299
|
// Update the store
|
|
255
300
|
if (requestedReportService) {
|
|
@@ -90,7 +90,15 @@ const renderSyncDashboard = async ({
|
|
|
90
90
|
query
|
|
91
91
|
);
|
|
92
92
|
const flattenedData = dashboardData.flat();
|
|
93
|
-
const
|
|
93
|
+
const dashboardFeatureFlags = Object.values(res.app.locals.featureFlags.flags).filter(
|
|
94
|
+
(flag) => flag.metadata["dashboardFeature"] === true
|
|
95
|
+
);
|
|
96
|
+
const sections = import_utils2.default.getSections(
|
|
97
|
+
dashboardDefinition,
|
|
98
|
+
flattenedData,
|
|
99
|
+
query,
|
|
100
|
+
dashboardFeatureFlags
|
|
101
|
+
);
|
|
94
102
|
await setAsRecentlyViewed({
|
|
95
103
|
req,
|
|
96
104
|
services,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../dpr/routes/journeys/view-report/sync/dashboard/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Request, Response } from 'express'\nimport Dict = NodeJS.Dict\n\nimport type { Services } from '../../../../../types/Services'\nimport { ReportType, RequestStatus } from '../../../../../types/UserReports'\nimport { FilterValue } from '../../../../../components/_filters/types'\nimport SelectedFiltersUtils from '../../../../../components/_filters/filters-selected/utils'\nimport LocalsHelper from '../../../../../utils/localsHelper'\nimport UserStoreItemBuilder from '../../../../../utils/UserStoreItemBuilder'\nimport { DashboardDataResponse } from '../../../../../types/Metrics'\nimport AsyncDashboardUtils from '../../async/dashboard/utils'\nimport { DashboardSection } from '../../../../../components/_dashboards/dashboard-visualisation/types'\nimport { components } from '../../../../../types/api'\nimport ReportActionsUtils from '../../../../../components/_reports/report-heading/report-actions/utils'\n\nconst setAsRecentlyViewed = async ({\n req,\n services,\n reportName,\n name,\n description,\n reportId,\n id,\n userId,\n filters,\n}: {\n req: Request\n services: Services\n reportName: string\n name: string\n description: string\n reportId: string\n id: string\n userId: string\n filters: FilterValue[]\n}) => {\n const stateData = {\n type: ReportType.DASHBOARD,\n reportId,\n id,\n reportName,\n description,\n name,\n }\n\n const interactiveQueryData: { query: Dict<string>; querySummary: Array<Dict<string>> } = {\n query: <Dict<string>>req.query,\n querySummary: SelectedFiltersUtils.getQuerySummary(<Dict<string>>req.query, filters),\n }\n\n const recentlyViewedData = new UserStoreItemBuilder(stateData)\n .addInteractiveQuery(interactiveQueryData)\n .addStatus(RequestStatus.READY)\n .addTimestamp()\n .addReportUrls(req)\n .build()\n\n await services.recentlyViewedService.setRecentlyViewed(recentlyViewedData, userId)\n}\n\nexport const renderSyncDashboard = async ({\n req,\n res,\n services,\n}: {\n req: Request\n res: Response\n services: Services\n}) => {\n const { token, csrfToken, dprUser, nestedBaseUrl } = LocalsHelper.getValues(res)\n const { reportId, id } = req.params\n const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`\n\n const {\n query,\n filters: filterData,\n reportDefinition,\n dashboardDefinition,\n } = await AsyncDashboardUtils.getDefinitionData({\n req,\n res,\n services,\n })\n\n const dashboardData: DashboardDataResponse[][] = await services.dashboardService.getSyncDashboard(\n token,\n id,\n reportId,\n query,\n )\n const flattenedData: DashboardDataResponse[] = dashboardData.flat()\n\n // Get the dashboard parts\n const sections: DashboardSection[] = AsyncDashboardUtils.getSections(dashboardDefinition
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,yBAA0C;AAE1C,mBAAiC;AACjC,0BAAyB;AACzB,kCAAiC;AAEjC,IAAAA,gBAAgC;AAGhC,IAAAA,gBAA+B;AAE/B,MAAM,sBAAsB,OAAO;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAUM;AACJ,QAAM,YAAY;AAAA,IAChB,MAAM,8BAAW;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,uBAAmF;AAAA,IACvF,OAAqB,IAAI;AAAA,IACzB,cAAc,aAAAC,QAAqB,gBAA8B,IAAI,OAAO,OAAO;AAAA,EACrF;AAEA,QAAM,qBAAqB,IAAI,4BAAAC,QAAqB,SAAS,EAC1D,oBAAoB,oBAAoB,EACxC,UAAU,iCAAc,KAAK,EAC7B,aAAa,EACb,cAAc,GAAG,EACjB,MAAM;AAET,QAAM,SAAS,sBAAsB,kBAAkB,oBAAoB,MAAM;AACnF;AAEO,MAAM,sBAAsB,OAAO;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACF,MAIM;AACJ,QAAM,EAAE,OAAO,WAAW,SAAS,cAAc,IAAI,oBAAAC,QAAa,UAAU,GAAG;AAC/E,QAAM,EAAE,UAAU,GAAG,IAAI,IAAI;AAC7B,QAAM,UAAU,GAAG,IAAI,QAAQ,MAAM,IAAI,IAAI,MAAM,CAAC,GAAG,IAAI,WAAW;AAEtE,QAAM;AAAA,IACJ;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF,IAAI,MAAM,cAAAC,QAAoB,kBAAkB;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAA2C,MAAM,SAAS,iBAAiB;AAAA,IAC/E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,gBAAyC,cAAc,KAAK;AAGlE,QAAM,WAA+B,cAAAA,QAAoB,
|
|
4
|
+
"sourcesContent": ["import type { Request, Response } from 'express'\nimport Dict = NodeJS.Dict\n\nimport type { Services } from '../../../../../types/Services'\nimport { ReportType, RequestStatus } from '../../../../../types/UserReports'\nimport { FilterValue } from '../../../../../components/_filters/types'\nimport SelectedFiltersUtils from '../../../../../components/_filters/filters-selected/utils'\nimport LocalsHelper from '../../../../../utils/localsHelper'\nimport UserStoreItemBuilder from '../../../../../utils/UserStoreItemBuilder'\nimport { DashboardDataResponse } from '../../../../../types/Metrics'\nimport AsyncDashboardUtils from '../../async/dashboard/utils'\nimport { DashboardSection } from '../../../../../components/_dashboards/dashboard-visualisation/types'\nimport { components } from '../../../../../types/api'\nimport ReportActionsUtils from '../../../../../components/_reports/report-heading/report-actions/utils'\n\nconst setAsRecentlyViewed = async ({\n req,\n services,\n reportName,\n name,\n description,\n reportId,\n id,\n userId,\n filters,\n}: {\n req: Request\n services: Services\n reportName: string\n name: string\n description: string\n reportId: string\n id: string\n userId: string\n filters: FilterValue[]\n}) => {\n const stateData = {\n type: ReportType.DASHBOARD,\n reportId,\n id,\n reportName,\n description,\n name,\n }\n\n const interactiveQueryData: { query: Dict<string>; querySummary: Array<Dict<string>> } = {\n query: <Dict<string>>req.query,\n querySummary: SelectedFiltersUtils.getQuerySummary(<Dict<string>>req.query, filters),\n }\n\n const recentlyViewedData = new UserStoreItemBuilder(stateData)\n .addInteractiveQuery(interactiveQueryData)\n .addStatus(RequestStatus.READY)\n .addTimestamp()\n .addReportUrls(req)\n .build()\n\n await services.recentlyViewedService.setRecentlyViewed(recentlyViewedData, userId)\n}\n\nexport const renderSyncDashboard = async ({\n req,\n res,\n services,\n}: {\n req: Request\n res: Response\n services: Services\n}) => {\n const { token, csrfToken, dprUser, nestedBaseUrl } = LocalsHelper.getValues(res)\n const { reportId, id } = req.params\n const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`\n\n const {\n query,\n filters: filterData,\n reportDefinition,\n dashboardDefinition,\n } = await AsyncDashboardUtils.getDefinitionData({\n req,\n res,\n services,\n })\n\n const dashboardData: DashboardDataResponse[][] = await services.dashboardService.getSyncDashboard(\n token,\n id,\n reportId,\n query,\n )\n const flattenedData: DashboardDataResponse[] = dashboardData.flat()\n\n // Get the dashboard parts\n const dashboardFeatureFlags = Object.values(res.app.locals.featureFlags.flags).filter(\n (flag) => flag.metadata['dashboardFeature'] === true,\n )\n const sections: DashboardSection[] = AsyncDashboardUtils.getSections(\n dashboardDefinition,\n flattenedData,\n query,\n dashboardFeatureFlags,\n )\n\n await setAsRecentlyViewed({\n req,\n services,\n reportName: reportDefinition.name,\n name: dashboardDefinition.name,\n description: dashboardDefinition.description || reportDefinition.description || '',\n reportId,\n id,\n userId: dprUser.id,\n filters: filterData.filters,\n })\n\n return {\n dashboardData: {\n token,\n id,\n reportId,\n name: dashboardDefinition.name,\n description: dashboardDefinition.description,\n reportName: reportDefinition.name,\n bookmarked: await services.bookmarkService.isBookmarked(id, reportId, dprUser.id),\n nestedBaseUrl,\n csrfToken,\n sections,\n filters: filterData,\n type: ReportType.DASHBOARD,\n actions: setActions(dashboardDefinition, reportDefinition, fullUrl),\n },\n }\n}\n\nexport const setActions = (\n definition: components['schemas']['DashboardDefinition'],\n summaryDefinition: components['schemas']['ReportDefinitionSummary'],\n url: string,\n) => {\n const { name: reportName } = summaryDefinition\n const { name } = definition\n\n return ReportActionsUtils.getActions({\n share: {\n reportName,\n name,\n url,\n },\n copy: {\n url,\n },\n })\n}\n\nexport default {\n renderSyncDashboard,\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,yBAA0C;AAE1C,mBAAiC;AACjC,0BAAyB;AACzB,kCAAiC;AAEjC,IAAAA,gBAAgC;AAGhC,IAAAA,gBAA+B;AAE/B,MAAM,sBAAsB,OAAO;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAUM;AACJ,QAAM,YAAY;AAAA,IAChB,MAAM,8BAAW;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,uBAAmF;AAAA,IACvF,OAAqB,IAAI;AAAA,IACzB,cAAc,aAAAC,QAAqB,gBAA8B,IAAI,OAAO,OAAO;AAAA,EACrF;AAEA,QAAM,qBAAqB,IAAI,4BAAAC,QAAqB,SAAS,EAC1D,oBAAoB,oBAAoB,EACxC,UAAU,iCAAc,KAAK,EAC7B,aAAa,EACb,cAAc,GAAG,EACjB,MAAM;AAET,QAAM,SAAS,sBAAsB,kBAAkB,oBAAoB,MAAM;AACnF;AAEO,MAAM,sBAAsB,OAAO;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACF,MAIM;AACJ,QAAM,EAAE,OAAO,WAAW,SAAS,cAAc,IAAI,oBAAAC,QAAa,UAAU,GAAG;AAC/E,QAAM,EAAE,UAAU,GAAG,IAAI,IAAI;AAC7B,QAAM,UAAU,GAAG,IAAI,QAAQ,MAAM,IAAI,IAAI,MAAM,CAAC,GAAG,IAAI,WAAW;AAEtE,QAAM;AAAA,IACJ;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF,IAAI,MAAM,cAAAC,QAAoB,kBAAkB;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAA2C,MAAM,SAAS,iBAAiB;AAAA,IAC/E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,gBAAyC,cAAc,KAAK;AAGlE,QAAM,wBAAwB,OAAO,OAAO,IAAI,IAAI,OAAO,aAAa,KAAK,EAAE;AAAA,IAC7E,CAAC,SAAS,KAAK,SAAS,kBAAkB,MAAM;AAAA,EAClD;AACA,QAAM,WAA+B,cAAAA,QAAoB;AAAA,IACvD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA,YAAY,iBAAiB;AAAA,IAC7B,MAAM,oBAAoB;AAAA,IAC1B,aAAa,oBAAoB,eAAe,iBAAiB,eAAe;AAAA,IAChF;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,SAAS,WAAW;AAAA,EACtB,CAAC;AAED,SAAO;AAAA,IACL,eAAe;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,oBAAoB;AAAA,MAC1B,aAAa,oBAAoB;AAAA,MACjC,YAAY,iBAAiB;AAAA,MAC7B,YAAY,MAAM,SAAS,gBAAgB,aAAa,IAAI,UAAU,QAAQ,EAAE;AAAA,MAChF;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,MAAM,8BAAW;AAAA,MACjB,SAAS,WAAW,qBAAqB,kBAAkB,OAAO;AAAA,IACpE;AAAA,EACF;AACF;AAEO,MAAM,aAAa,CACxB,YACA,mBACA,QACG;AACH,QAAM,EAAE,MAAM,WAAW,IAAI;AAC7B,QAAM,EAAE,KAAK,IAAI;AAEjB,SAAO,cAAAC,QAAmB,WAAW;AAAA,IACnC,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,IAAO,gBAAQ;AAAA,EACb;AACF;",
|
|
6
6
|
"names": ["import_utils", "SelectedFiltersUtils", "UserStoreItemBuilder", "LocalsHelper", "AsyncDashboardUtils", "ReportActionsUtils"]
|
|
7
7
|
}
|
|
@@ -91,7 +91,15 @@ export const renderSyncDashboard = async ({
|
|
|
91
91
|
const flattenedData: DashboardDataResponse[] = dashboardData.flat()
|
|
92
92
|
|
|
93
93
|
// Get the dashboard parts
|
|
94
|
-
const
|
|
94
|
+
const dashboardFeatureFlags = Object.values(res.app.locals.featureFlags.flags).filter(
|
|
95
|
+
(flag) => flag.metadata['dashboardFeature'] === true,
|
|
96
|
+
)
|
|
97
|
+
const sections: DashboardSection[] = AsyncDashboardUtils.getSections(
|
|
98
|
+
dashboardDefinition,
|
|
99
|
+
flattenedData,
|
|
100
|
+
query,
|
|
101
|
+
dashboardFeatureFlags,
|
|
102
|
+
)
|
|
95
103
|
|
|
96
104
|
await setAsRecentlyViewed({
|
|
97
105
|
req,
|
|
@@ -28,8 +28,8 @@ class FeatureFlagService {
|
|
|
28
28
|
restClient;
|
|
29
29
|
namespace;
|
|
30
30
|
constructor(config = {}) {
|
|
31
|
-
const {
|
|
32
|
-
if (Object.keys(config).length !==
|
|
31
|
+
const { token, url } = config && config;
|
|
32
|
+
if (Object.keys(config).length !== 2 || !token || !url) {
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
this.restClient = new import_flipt.FliptClient({
|
|
@@ -39,7 +39,7 @@ class FeatureFlagService {
|
|
|
39
39
|
},
|
|
40
40
|
url
|
|
41
41
|
});
|
|
42
|
-
this.namespace =
|
|
42
|
+
this.namespace = "hmpps-digital-prison-reporting";
|
|
43
43
|
}
|
|
44
44
|
async getFlags() {
|
|
45
45
|
if (!this.restClient || !this.namespace) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../dpr/services/featureFlagService.ts"],
|
|
4
|
-
"sourcesContent": ["import { FliptClient, ListFlagsResponse } from '@flipt-io/flipt'\nimport { Application } from 'express'\nimport { FeatureFlagConfig } from '../data/types'\n\nexport class FeatureFlagService {\n restClient: FliptClient | undefined\n\n namespace: string | undefined\n\n constructor(config: FeatureFlagConfig | Record<string, unknown> = {}) {\n const {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;
|
|
4
|
+
"sourcesContent": ["import { FliptClient, ListFlagsResponse } from '@flipt-io/flipt'\nimport { Application } from 'express'\nimport { FeatureFlagConfig } from '../data/types'\n\n// Override this until types are fixed - metadata is returned, but not in the types\ndeclare module '@flipt-io/flipt' {\n interface Flag {\n metadata: Record<string, string | boolean | number>\n }\n}\n\nexport class FeatureFlagService {\n restClient: FliptClient | undefined\n\n namespace: string | undefined\n\n constructor(config: FeatureFlagConfig | Record<string, unknown> = {}) {\n const { token, url } = config && (config as FeatureFlagConfig)\n if (Object.keys(config).length !== 2 || !token || !url) {\n return\n }\n this.restClient = new FliptClient({\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n url,\n })\n this.namespace = 'hmpps-digital-prison-reporting'\n }\n\n async getFlags(): Promise<ListFlagsResponse> {\n if (!this.restClient || !this.namespace) {\n return {\n flags: [],\n nextPageToken: '',\n totalCount: 0,\n }\n }\n return this.restClient.flags.listFlags(this.namespace)\n }\n}\n\nconst resolveFlag = (app: Application, flagName: string) => {\n const flag = app.locals.featureFlags?.flags?.[flagName]\n if (flag && flag.type !== 'BOOLEAN_FLAG_TYPE') {\n throw Error('Tried to validate whether a non-boolean flag was enabled')\n }\n return flag\n}\n\nexport const isBooleanFlagEnabledOrMissing = (flagName: string, app: Application): boolean => {\n const flag = resolveFlag(app, flagName)\n return !flag || flag.enabled\n}\n\nexport const isBooleanFlagExplicitlyEnabled = (flagName: string, app: Application): boolean => {\n return resolveFlag(app, flagName)?.enabled === true\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;AAWxC,MAAM,mBAAmB;AAAA,EAC9B;AAAA,EAEA;AAAA,EAEA,YAAY,SAAsD,CAAC,GAAG;AACpE,UAAM,EAAE,OAAO,IAAI,IAAI,UAAW;AAClC,QAAI,OAAO,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC,SAAS,CAAC,KAAK;AACtD;AAAA,IACF;AACA,SAAK,aAAa,IAAI,yBAAY;AAAA,MAChC,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,QAC9B,gBAAgB;AAAA,MAClB;AAAA,MACA;AAAA,IACF,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,WAAuC;AAC3C,QAAI,CAAC,KAAK,cAAc,CAAC,KAAK,WAAW;AACvC,aAAO;AAAA,QACL,OAAO,CAAC;AAAA,QACR,eAAe;AAAA,QACf,YAAY;AAAA,MACd;AAAA,IACF;AACA,WAAO,KAAK,WAAW,MAAM,UAAU,KAAK,SAAS;AAAA,EACvD;AACF;AAEA,MAAM,cAAc,CAAC,KAAkB,aAAqB;AAC1D,QAAM,OAAO,IAAI,OAAO,cAAc,QAAQ,QAAQ;AACtD,MAAI,QAAQ,KAAK,SAAS,qBAAqB;AAC7C,UAAM,MAAM,0DAA0D;AAAA,EACxE;AACA,SAAO;AACT;AAEO,MAAM,gCAAgC,CAAC,UAAkB,QAA8B;AAC5F,QAAM,OAAO,YAAY,KAAK,QAAQ;AACtC,SAAO,CAAC,QAAQ,KAAK;AACvB;AAEO,MAAM,iCAAiC,CAAC,UAAkB,QAA8B;AAC7F,SAAO,YAAY,KAAK,QAAQ,GAAG,YAAY;AACjD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,14 +2,21 @@ import { FliptClient, ListFlagsResponse } from '@flipt-io/flipt'
|
|
|
2
2
|
import { Application } from 'express'
|
|
3
3
|
import { FeatureFlagConfig } from '../data/types'
|
|
4
4
|
|
|
5
|
+
// Override this until types are fixed - metadata is returned, but not in the types
|
|
6
|
+
declare module '@flipt-io/flipt' {
|
|
7
|
+
interface Flag {
|
|
8
|
+
metadata: Record<string, string | boolean | number>
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
export class FeatureFlagService {
|
|
6
13
|
restClient: FliptClient | undefined
|
|
7
14
|
|
|
8
15
|
namespace: string | undefined
|
|
9
16
|
|
|
10
17
|
constructor(config: FeatureFlagConfig | Record<string, unknown> = {}) {
|
|
11
|
-
const {
|
|
12
|
-
if (Object.keys(config).length !==
|
|
18
|
+
const { token, url } = config && (config as FeatureFlagConfig)
|
|
19
|
+
if (Object.keys(config).length !== 2 || !token || !url) {
|
|
13
20
|
return
|
|
14
21
|
}
|
|
15
22
|
this.restClient = new FliptClient({
|
|
@@ -19,7 +26,7 @@ export class FeatureFlagService {
|
|
|
19
26
|
},
|
|
20
27
|
url,
|
|
21
28
|
})
|
|
22
|
-
this.namespace =
|
|
29
|
+
this.namespace = 'hmpps-digital-prison-reporting'
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
async getFlags(): Promise<ListFlagsResponse> {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ministryofjustice/hmpps-digital-prison-reporting-frontend",
|
|
3
3
|
"description": "The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.30.1",
|
|
5
5
|
"main": "dpr/all",
|
|
6
6
|
"sass": "dpr/all.scss",
|
|
7
7
|
"engines": {
|
|
@@ -194,7 +194,6 @@
|
|
|
194
194
|
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
|
195
195
|
"@typescript-eslint/parser": "^5.62.0",
|
|
196
196
|
"audit-ci": "^6.6.1",
|
|
197
|
-
"autoprefixer": "^10.4.15",
|
|
198
197
|
"axe-core": "^4.9.0",
|
|
199
198
|
"cypress": "^14.5.4",
|
|
200
199
|
"cypress-axe": "^1.6.0",
|