Skip to content

Commit 49f42fd

Browse files
authored
Merge pull request #349 from bcgov/applicationscore-poc
OFMCC-7594,7477
2 parents 096c271 + 815c122 commit 49f42fd

File tree

16 files changed

+9672
-9551
lines changed

16 files changed

+9672
-9551
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"use strict";
2+
3+
var OFM = OFM || {};
4+
OFM.application_score_calculator = OFM.application_score_calculator || {};
5+
OFM.application_score_calculator.Ribbon = OFM.application_score_calculator.Ribbon || {};
6+
7+
OFM.application_score_calculator.Ribbon = {
8+
9+
approveCalculator: function (primaryControl) {
10+
var formContext = primaryControl;
11+
var entityId = formContext.data.entity.getId().replace("{", "").replace("}", "");
12+
var entityName = formContext.data.entity.getEntityName();
13+
14+
var data = {
15+
"statuscode": 1 // Set statuscode to 1 (e.g., Active)
16+
};
17+
18+
Xrm.WebApi.updateRecord(entityName, entityId, data).then(
19+
function success(result) {
20+
Xrm.Navigation.openAlertDialog({ text: "Status updated successfully!" });
21+
formContext.data.refresh(false); // Refresh form without saving
22+
},
23+
function error(error) {
24+
Xrm.Navigation.openAlertDialog({ text: "Error updating status: " + error.message });
25+
}
26+
);
27+
},
28+
29+
isApproveVisible: function (primaryControl) {
30+
var userId = Xrm.Utility.getGlobalContext().userSettings.userId.replace("{", "").replace("}", "");
31+
var fetchData = {
32+
"role1": "OFM - System Administrator",
33+
"role2": "System Administrator",
34+
"systemuserid": userId
35+
};
36+
var fetchXmlTeams = [
37+
"<fetch top='50' aggregate='true'>",
38+
" <entity name='role'>",
39+
" <attribute name='name' alias='count' aggregate='count'/>",
40+
" <filter>",
41+
" <condition attribute='name' operator='in'>",
42+
" <value>", fetchData.role1/*OFM - System Administrator*/, "</value>",
43+
" <value>", fetchData.role2/*OFM - System Administrator*/, "</value>",
44+
" </condition>",
45+
" </filter>",
46+
" <link-entity name='teamroles' from='roleid' to='roleid' intersect='true'>",
47+
" <link-entity name='team' from='teamid' to='teamid' intersect='true'>",
48+
" <link-entity name='teammembership' from='teamid' to='teamid' intersect='true'>",
49+
" <link-entity name='systemuser' from='systemuserid' to='systemuserid' intersect='true'>",
50+
" <filter>",
51+
" <condition attribute='systemuserid' operator='eq' value='", fetchData.systemuserid/*5de6fde2-ef16-f011-998a-7ced8d05e0a9*/, "' uiname='Harpreet Singh-Hans' uitype='systemuser'/>",
52+
" </filter>",
53+
" </link-entity>",
54+
" </link-entity>",
55+
" </link-entity>",
56+
" </link-entity>",
57+
" </entity>",
58+
"</fetch>"
59+
].join("");
60+
61+
var fetchXmlUsers = [
62+
"<fetch top='50' aggregate='true'>",
63+
" <entity name='role'>",
64+
" <attribute name='name' alias='count' aggregate='count'/>",
65+
" <filter>",
66+
" <condition attribute='name' operator='in'>",
67+
" <value>", fetchData.role1/*OFM - System Administrator*/, "</value>",
68+
" <value>", fetchData.role2/*OFM - System Administrator*/, "</value>",
69+
" </condition>",
70+
" </filter>",
71+
" <link-entity name='systemuserroles' from='roleid' to='roleid' intersect='true'>",
72+
" <filter>",
73+
" <condition attribute='systemuserid' operator='eq' value='", fetchData.systemuserid/*00000000-0000-0000-0000-000000000000*/, "'/>",
74+
" </filter>",
75+
" </link-entity>",
76+
" </entity>",
77+
"</fetch>"
78+
].join("");
79+
80+
var roleQuery1 = "?fetchXml=" + fetchXmlTeams;
81+
var roleQuery2 = "?fetchXml=" + fetchXmlUsers;
82+
83+
Promise.all([Xrm.WebApi.retrieveMultipleRecords("role", roleQuery1), Xrm.WebApi.retrieveMultipleRecords("role", roleQuery2)])
84+
.then((results) => {
85+
let roleCount = results.reduce((sum, res) => sum + (res.entities.length > 0 ? res.entities[0].count : 0), 0);
86+
return roleCount > 0;
87+
})
88+
.catch((error) => {
89+
console.error("Error retrieving user teams: " + error.message);
90+
return false;
91+
});
92+
93+
}
94+
};

OFM.Infrastructure.PCF/Controls/ApplicationScoreGauge/ScoreGauge/ControlManifest.Input.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest>
3-
<control namespace="ECC.PCF" constructor="ApplicationScoreGaugeControl" version="0.0.12" display-name-key="Application Score Gauge" description-key="Displays an application score as a gauge chart" control-type="standard">
3+
<control namespace="ECC.PCF" constructor="ApplicationScoreGaugeControl" version="0.0.19" display-name-key="Application Score Gauge" description-key="Displays an application score as a gauge chart" control-type="standard">
44
<property name="score" display-name-key="Score" description-key="The score to display on the gauge" of-type="Whole.None" usage="bound" required="true" />
55
<property name="maxScore" display-name-key="MaxScore" description-key="The Max score to display on the gauge" of-type="Whole.None" usage="bound" required="true" />
66
<resources>

OFM.Infrastructure.PCF/Controls/ApplicationScoreGauge/ScoreGauge/gauge/GaugeChart.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,32 @@ export const GaugeChartComponent: React.FC<GaugeChartProps> = ({ score, maxScore
3535
fill: "#323130",
3636
},
3737
};
38+
39+
40+
const lowScore = () => {
41+
return roundOff(maxScore * (lowSegmentPercent / 100))
42+
}
43+
const mediumScore = () => {
44+
45+
return roundOff(maxScore * (mediumSegmentPercent / 100))
46+
}
47+
48+
49+
50+
const roundOff = (num: number, decimalPlaces: number = 0): number => {
51+
if(num == null) return 0;
52+
const multiplier = Math.pow(10, decimalPlaces);
53+
return Math.round(num * multiplier) / multiplier;
54+
};
3855
// Gauge chart configuration
3956
const gaugeProps: IGaugeChartProps = {
4057
chartValue: score !== null ? score : 0,
4158
styles: gaugeStyles,
4259
maxValue: maxScore,
4360
segments: [
44-
{ size: maxScore * (lowSegmentPercent / 100), gradient: getGradientFromToken(DataVizGradientPalette.error), color: "#d13438", legend: lowSegmentLabel },
45-
{ size: maxScore * (mediumSegmentPercent / 100), gradient: getGradientFromToken(DataVizGradientPalette.warning), color: "#d29200", legend: mediumSegmentLabel },
46-
{ size: maxScore * (highSegmentPercent / 100), gradient: getGradientFromToken(DataVizGradientPalette.success), color: "#107c10", legend: highSegmentLabel },
61+
{ size: lowScore(), gradient: getGradientFromToken(DataVizGradientPalette.error), color: "#d13438", legend: lowSegmentLabel },
62+
{ size: mediumScore(), gradient: getGradientFromToken(DataVizGradientPalette.warning), color: "#d29200", legend: mediumSegmentLabel },
63+
{ size: maxScore - lowScore() - mediumScore(), gradient: getGradientFromToken(DataVizGradientPalette.success), color: "#107c10", legend: highSegmentLabel },
4764
],
4865
width: 300,
4966
height: 150,

OFM.Infrastructure.PCF/Controls/ApplicationScoreGauge/Solution/ScoreGaugePCF/src/Other/Solution.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<LocalizedName description="ScoreGaugePCF" languagecode="1033" />
99
</LocalizedNames>
1010
<Descriptions />
11-
<Version>1.0.10</Version>
11+
<Version>1.0.17</Version>
1212
<!-- Solution Package Type: Unmanaged(0)/Managed(1)/Both(2)-->
1313
<Managed>2</Managed>
1414
<Publisher>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": [
7+
"eslint:recommended",
8+
"plugin:react/recommended"
9+
],
10+
"globals": {
11+
"ComponentFramework": true
12+
},
13+
"parser": "@typescript-eslint/parser",
14+
"parserOptions": {
15+
"ecmaVersion": 12,
16+
"sourceType": "module"
17+
},
18+
"plugins": [
19+
"@typescript-eslint"
20+
],
21+
"rules": {
22+
}
23+
}

OFM.Infrastructure.PCF/Controls/PAGridCustomizer/PowerAppsGridCustomizer/ControlManifest.Input.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest>
3-
<control namespace="ECC.PCF" constructor="PowerAppsGridCustomizer" version="0.0.35" display-name-key="PowerAppsGridCustomizer" description-key="PowerAppsGridCustomizer description" control-type="standard">
3+
<control namespace="ECC.PCF" constructor="PowerAppsGridCustomizer" version="0.0.52" display-name-key="PowerAppsGridCustomizer" description-key="PowerAppsGridCustomizer description" control-type="standard">
44
<property name="EventName" display-name-key="EventName" description-key="EventName" of-type="SingleLine.Text" usage="bound" required="true" />
55
<resources>
66
<code path="index.ts" order="1" />
Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,65 @@
11
import { Label } from "@fluentui/react";
2-
import RadialControl from "./RadialControl"
2+
import {RadialControl, RadialControlSpecial }from "./RadialControl"
33
import * as React from "react";
4-
import { CellRendererProps, CellRendererOverrides } from "../types";
4+
import { CellRendererProps, GetRendererParams, RECID } from "../types";
55

6-
export const cellRendererOverrides: CellRendererOverrides = {
7-
["Text"]: (props: CellRendererProps, col) => {
8-
// Only override the cell renderer for the score column
9-
if (col.colDefs[col.columnIndex].name === "ofm_score" || col.colDefs[col.columnIndex].name === "ofm_application_score_total") {
10-
const score = Number(props.value);
11-
const tooltip = props.value;
6+
export const generateCellRendererOverrides = (webAPI: ComponentFramework.WebApi, peopleCache = {}) => {
7+
8+
return {
9+
["Text"]: (props: CellRendererProps, rendererParams: GetRendererParams) => {
10+
const { columnIndex, colDefs, rowData } = rendererParams;
11+
12+
13+
// Only override the cell renderer for the score column
14+
if (colDefs[columnIndex].name === "ofm_score") {
15+
const score = Number(props.value);
16+
const tooltip = props.value;
1217
// Render the cell value in green when the value is gte 0 and red otherwise
13-
if (isNaN(score)) {
18+
if (isNaN(score)) {
1419
return (<RadialControl tooltip={String(tooltip)} size="35px" color="Red">
15-
<span style={{ fontWeight: "bold", color: "white" }} >N/A</span>
16-
</RadialControl>);
20+
<span style={{ fontWeight: "bold", color: "white" }} >N/A</span>
21+
</RadialControl>);
1722

18-
}
19-
else if ((props.value as number) >= 0) {
23+
}
24+
else if ((props.value as number) >= 0) {
2025
return (<RadialControl tooltip={""} size="35px" color="Gray">
21-
<span style={{ fontWeight: "bold", color: "white" }} >{props.formattedValue}</span>
22-
</RadialControl>);
23-
}
24-
}
25-
},
26-
["Integer"]: (props: CellRendererProps, col) => {
27-
// Only override the cell renderer for the score column
28-
if (col.colDefs[col.columnIndex].name === "ofm_score" || col.colDefs[col.columnIndex].name === "ofm_application_score_total") {
29-
const score = Number(props.value);
30-
const tooltip = props.value;
31-
// Render the cell value in Gray when the value is gte 0 and red otherwise
32-
if (isNaN(score)) {
33-
return (<RadialControl tooltip={String(tooltip)} size="35px" color="Red">
34-
<span style={{ fontWeight: "bold", color: "white" }} >{props.formattedValue}</span>
35-
</RadialControl>);
36-
26+
<span style={{ fontWeight: "bold", color: "white" }} >{props.formattedValue}</span>
27+
</RadialControl>);
28+
}
3729
}
38-
else if ((props.value as number) >= 0) {
30+
},
31+
["Integer"]: (props: CellRendererProps, rendererParams: GetRendererParams) => {
32+
// Only override the cell renderer for the score column
33+
const { columnIndex, colDefs, rowData } = rendererParams;
34+
35+
if (colDefs[columnIndex].name === "ofm_score") {
36+
const score = Number(props.value);
37+
const tooltip = props.value;
38+
// Render the cell value in Gray when the value is gte 0 and red otherwise
39+
if (isNaN(score)) {
40+
return (<RadialControl tooltip={String(tooltip)} size="35px" color="Red">
41+
<span style={{ fontWeight: "bold", color: "white" }} >{props.formattedValue}</span>
42+
</RadialControl>);
43+
44+
}
45+
else if ((props.value as number) >= 0) {
3946
return (<RadialControl tooltip={""} size="35px" color="Gray">
40-
<span style={{ fontWeight: "bold", color: "white" }} >{props.formattedValue}</span>
41-
</RadialControl>);
47+
<span style={{ fontWeight: "bold", color: "white" }} >{props.formattedValue}</span>
48+
</RadialControl>);
49+
}
50+
}
51+
52+
if (colDefs[columnIndex].name === "ofm_application_score_total") {
53+
const score = Number(props.value);
54+
const tooltip = props.value;
55+
// Render the cell value in Gray when the value is gte 0 and red otherwise
56+
57+
return (<RadialControlSpecial tooltip={String(tooltip)} size="35px" color="White" parentId={ rowData?.[RECID] } webAPI={webAPI} peopleCache={peopleCache} >
58+
<span style={{ fontWeight: "bold", color: "black" }}>{props.formattedValue}</span>
59+
</RadialControlSpecial>);
60+
61+
4262
}
4363
}
44-
},
64+
}
4565
};

0 commit comments

Comments
 (0)