Forum Discussion
Please help clean Jira connector code
Hi everyone!
We've got Jira Service Management Cloud and Power BI Desktop with a connector. Currently I need to add one more column with Reaction SLA by Hour. The issue is: the data is in JSON format so duplicating the column with the same parent data fileds lead to an error: data can be accessed via Editor but is not avalable from the application.
Feedback Type:
Frown (Error)
Error Message:
An error occurred while rendering the report.
Stack Trace:
Microsoft.PowerBI.Client.Windows.JavaScriptException
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: prop in $ctrl.viewModel.properties | filter:$ctrl.filterProperties, Duplicate key: object:261, Duplicate value: {"hasCheckedChildren":false,"contract":{"displayName":"Resolution breach Hour","name":"Resolution breach Hour","type":{"underlyingType":260,"category":null},"column":{"defaultAggregate":2,"variations":[]},"kind":0,"format":"0","canDelete":true},"schema":{"entities":[{"name":"Jira-Issues","displayName":"Jira-Issues","visibility":0,"properties":
I've got little knowledge in M so I can't understand how to fix the code. Please help me clean the code:
let
Issues = let
Issues = let
Source = JiraData,
#"Expanded fields" = Table.ExpandRecordColumn(Source, "fields", Text.Split(FieldsToGet,",")),
#"Expanded assignee" = Table.ExpandRecordColumn(#"Expanded fields", "assignee", {"displayName"}, {"Assignee"}),
#"Expanded reporter" = Table.ExpandRecordColumn(#"Expanded assignee", "reporter", {"displayName"}, {"Reporter"}),
#"Replace null assignee" = Table.TransformColumns(#"Expanded reporter", {"Assignee", each if _ is null then "Unassigned" else _}),
#"Expanded project" = Table.ExpandRecordColumn(#"Replace null assignee", "project", {"key", "name"}, {"Project", "Project Name"}),
#"Transform project name" = Table.ReplaceValue(#"Expanded project", each [Project Name], each [Project Name] & " (" & [Project] & ")", Replacer.ReplaceText, {"Project Name"}),
#"Expanded priority" = Table.ExpandRecordColumn(#"Transform project name", "priority", {"name", "id", "iconUrl"}, {"Priority", "Priority Id", "Priority Icon URL"}),
#"Expanded issuetype" = Table.ExpandRecordColumn(#"Expanded priority", "issuetype", {"name", "subtask"}, {"Issue Type", "Is Subtask"}),
#"Expanded status" = Table.ExpandRecordColumn(#"Expanded issuetype", "status", {"name", "id", "iconUrl"}, {"Status", "Status Id", "Status Icon URL"}),
#"Expanded resolution" = Table.ExpandRecordColumn(#"Expanded status", "resolution", {"name"}, {"Resolution"}),
#"Expanded components" = Table.ExpandListColumn(#"Expanded resolution", "components"),
#"Expanded components1" = Table.ExpandRecordColumn(#"Expanded components", "components", {"name"}, {"Components"}),
#"Replace null resolution" = Table.TransformColumns(#"Expanded components1", {"Resolution", each if _ is null then "Unresolved" else _}),
#"Changed Type" = Table.TransformColumnTypes(#"Replace null resolution",{{"created", type datetimezone}, {"updated", type datetimezone}, {"resolutiondate", type datetimezone}, {"id", Int64.Type}, {"Priority Id", Int64.Type}}),
#"Add hour created" = Table.AddColumn(#"Changed Type", "Hour created", each Time.Hour([created]), Int64.Type),
#"Add date created" = Table.AddColumn(#"Add hour created", "Date Created", each Date.From([created]), type date),
#"Add week created" = Table.AddColumn(#"Add date created", "Week Created", each Date.EndOfWeek([Date Created]), type date),
#"Add date updated" = Table.AddColumn(#"Add week created", "Date Updated", each Date.From([updated]), type date),
#"Add week updated" = Table.AddColumn(#"Add date updated", "Week Updated", each Date.EndOfWeek([Date Updated]), type date),
#"Add date resolved" = Table.AddColumn(#"Add week updated", "Date Resolved", each Date.From([resolutiondate]), type date),
#"Add week resolution" = Table.AddColumn(#"Add date resolved", "Week Resolved", each Date.EndOfWeek([Date Resolved]), type date),
#"Add Is Resolved" = Table.AddColumn(#"Add week resolution", "Is Resolved", each if [Date Resolved] <> null or List.Contains({"Cancelled","Closed","Done"}, [Status]) then 1 else 0, Int32.Type),
#"Add Resolution Status" = Table.AddColumn(#"Add Is Resolved", "Resolution Status", each if [Is Resolved] = 1 then "Resolved" else "Unresolved", type text),
#"Removed columns" = Table.RemoveColumns(#"Add Resolution Status", {"expand","Meta","Timestamp","created","updated","resolutiondate"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed columns",{{"id", "Issue Id"}, {"key", "Issue Key"}, {"self", "Issue URL"}, {"summary", "Summary"}}),
#"Transform issue URL" = Table.ReplaceValue(#"Renamed Columns", each [Issue URL], each JiraURL & "/browse/" & [Issue Key], Replacer.ReplaceText, {"Issue URL"})
in
#"Transform issue URL",
#"Expanded customfield_10103" = Table.ExpandRecordColumn(Issues, "customfield_10103", {"value"}, {"MCS Service"}),
#"Renamed Columns" = Table.RenameColumns(#"Expanded customfield_10103",{{"customfield_10101", "Resource ID"}, {"customfield_10105", "Request channel"}, {"customfield_10024", "Satisfaction"}, {"customfield_10099", "MCS Project"}, {"customfield_10002", "Organization"}}),
#"Expanded Organization" = Table.ExpandListColumn(#"Renamed Columns", "Organization"),
#"Expanded Organization1" = Table.ExpandRecordColumn(#"Expanded Organization", "Organization", {"name"}, {"name"}),
#"Renamed Columns1" = Table.RenameColumns(#"Expanded Organization1",{{"name", "Organization"}}),
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns1", each true),
#"Duplicate SLA Reaction" = Table.DuplicateColumn(#"Filtered Rows", "customfield_10038", "SLA Reaction Hour"),
#"Renamed Columns2" = Table.RenameColumns(#"Duplicate SLA Reaction",{{"customfield_10038", "Reaction"}}),
#"Expanded Reaction" = Table.ExpandRecordColumn(#"Renamed Columns2", "Reaction", {"completedCycles"}, {"breached"})
in
#"Renamed Columns2",
#"Expanded Reaction" = Table.ExpandRecordColumn(Issues, "Reaction", {"completedCycles"}, {"completedCycles"}),
#"Expanded completedCycles" = Table.ExpandListColumn(#"Expanded Reaction", "completedCycles"),
#"Expanded completedCycles1" = Table.ExpandRecordColumn(#"Expanded completedCycles", "completedCycles", {"breached"}, {"breached"}),
#"Expanded Request channel" = Table.ExpandRecordColumn(#"Expanded completedCycles1", "Request channel", {"value"}, {"value"}),
#"Renamed Columns" = Table.RenameColumns(#"Expanded Request channel",{{"breached", "SLA Reaction"}, {"value", "Request channel"}}),
#"Duplicate SLA Resolution" = Table.DuplicateColumn(#"Renamed Columns", "customfield_10037", "SLA Resolution Hour"),
#"Expanded SLA Resolution Hour" = Table.ExpandRecordColumn(#"Duplicate SLA Resolution", "SLA Resolution Hour", {"id", "name", "_links", "completedCycles", "ongoingCycle"}),
#"Expanded customfield_10037" = Table.ExpandRecordColumn(#"Duplicate SLA Resolution", "customfield_10037", {"completedCycles"}, {"completedCycles"}),
#"Expanded completedCycles2" = Table.ExpandListColumn(#"Expanded customfield_10037", "completedCycles"),
#"Expanded completedCycles3" = Table.ExpandRecordColumn(#"Expanded completedCycles2", "completedCycles", {"breached"}, {"breached"}),
#"Renamed Columns1" = Table.RenameColumns(#"Expanded completedCycles3",{{"breached", "SLA Resolution"}}),
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns1",{"Status Id", "Status Icon URL", "Priority Id", "Priority Icon URL"}),
#"Expanded issuelinks" = Table.ExpandListColumn(#"Removed Columns", "issuelinks"),
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded issuelinks", "issuelinks", "issuelinks - Copy"),
#"Expanded issuelinks1" = Table.ExpandRecordColumn(#"Duplicated Column", "issuelinks", {"outwardIssue"}, {"outwardIssue"}),
#"Expanded outwardIssue" = Table.ExpandRecordColumn(#"Expanded issuelinks1", "outwardIssue", {"key"}, {"key"}),
#"Renamed Columns2" = Table.RenameColumns(#"Expanded outwardIssue",{{"key", "LinkedIssue"}}),
#"Expanded issuelinks - Copy" = Table.ExpandRecordColumn(#"Renamed Columns2", "issuelinks - Copy", {"type"}, {"type"}),
#"Expanded type" = Table.ExpandRecordColumn(#"Expanded issuelinks - Copy", "type", {"outward"}, {"outward"}),
#"Renamed Columns3" = Table.RenameColumns(#"Expanded type",{{"outward", "LinkedType"}}),
#"Add Is Escalated" = Table.AddColumn(#"Renamed Columns3", "Is Escalated", each if [LinkedType] = "causes" then 1 else 0, Int32.Type),
#"Expanded customfield_10061" = Table.ExpandRecordColumn(#"Add Is Escalated", "customfield_10061", {"value"}, {"value"}),
#"Renamed Columns4" = Table.RenameColumns(#"Expanded customfield_10061",{{"value", "Alert Component"}}),
#"Expanded customfield_10060" = Table.ExpandRecordColumn(#"Renamed Columns4", "customfield_10060", {"value"}, {"value"}),
#"Renamed Columns5" = Table.RenameColumns(#"Expanded customfield_10060",{{"value", "Alert Reason"}}),
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns5", each Date.IsInCurrentYear([Date Created])),
#"Expanded SLA Resolution Hour1" = Table.ExpandRecordColumn(#"Filtered Rows", "SLA Resolution Hour", {"ongoingCycle"}, {"ongoingCycle"}),
#"Expanded ongoingCycle" = Table.ExpandRecordColumn(#"Expanded SLA Resolution Hour1", "ongoingCycle", {"breachTime"}, {"breachTime"}),
#"Expanded breachTime" = Table.ExpandRecordColumn(#"Expanded ongoingCycle", "breachTime", {"iso8601"}, {"iso8601"}),
#"Changed Type" = Table.TransformColumnTypes(#"Expanded breachTime",{{"iso8601", type datetimezone}}),
#"Extracted Hour" = Table.TransformColumns(#"Changed Type",{{"iso8601", Time.Hour, Int64.Type}}),
#"Renamed Columns6" = Table.RenameColumns(#"Extracted Hour",{{"iso8601", "Resolution breach Hour"}}),
#"Expanded SLA Reaction Hour" = Table.ExpandRecordColumn(#"Renamed Columns6", "SLA Reaction Hour", {"completedCycles"}, {"completedCycles"}),
#"Expanded completedCycles4" = Table.ExpandListColumn(#"Expanded SLA Reaction Hour", "completedCycles"),
#"Expanded completedCycles5" = Table.ExpandRecordColumn(#"Expanded completedCycles4", "completedCycles", {"stopTime"}, {"stopTime"}),
#"Expanded stopTime" = Table.ExpandRecordColumn(#"Expanded completedCycles5", "stopTime", {"iso8601"}, {"iso8601"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Expanded stopTime",{{"iso8601", type datetimezone}}),
#"Extracted SLA Resolution Hour" = Table.TransformColumns(#"Changed Type1",{{"iso8601", Time.Hour, Int64.Type}}),
#"Renamed Columns7" = Table.RenameColumns(#"Extracted SLA Resolution Hour",{{"iso8601", "Reaction breach Hour"}})
in
#"Renamed Columns7"
2 Replies
- v-lionel-msftCommunity Support
Hi alexey-denisov ,
Solved: JIRA to Power BI - Microsoft Power BI Community
Maybe you can use rest api.
Best regards,
Lionel ChenIf this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
- alexey-denisovFrequent Visitor
Hi v-lionel-msft !
Unfortunately my code has more data than the paid Jira plugin you've mentioned.
In fact my error is related to the columns expanding operations that I have.
Duplicating the columns with the names "completedCycles" (or else in the Expand steps) causes Power BI Desktop App to crash.
If I delete customfield_10038 everything works good.
So please help me understand how to get the values from the field
customfiled_10038->completedCycles->stopTime->iso8601 in Hour formatin a more direct way within (if possible) only 1 line.
The part of Jira JSON for those customfields look like:
"customfield_10038": { "id": "47", "name": "Time to first response", "_links": { "self": "https://_domain_.atlassian.net/rest/servicedeskapi/request/30425/sla/47" }, "completedCycles": [ { "startTime": { "iso8601": "2021-03-21T17:08:56+0300", "jira": "2021-03-21T17:08:56.247+0300", "friendly": "21.03.2021 17:08", "epochMillis": 1616335736247 }, "stopTime": { "iso8601": "2021-03-21T17:10:02+0300", "jira": "2021-03-21T17:10:02.669+0300", "friendly": "21.03.2021 17:10", "epochMillis": 1616335802669 }, "breached": false, "goalDuration": { "millis": 1800000, "friendly": "30m" }, "elapsedTime": { "millis": 66422, "friendly": "1m" }, "remainingTime": { "millis": 1733578, "friendly": "28m" } } ] },and
"customfield_10037": { "id": "49", "name": "Time to resolution", "_links": { "self": "https://_domain_.atlassian.net/rest/servicedeskapi/request/30425/sla/49" }, "completedCycles": [ { "startTime": { "iso8601": "2021-03-21T17:08:56+0300", "jira": "2021-03-21T17:08:56.247+0300", "friendly": "21.03.2021 17:08", "epochMillis": 1616335736247 }, "stopTime": { "iso8601": "2021-03-21T17:19:16+0300", "jira": "2021-03-21T17:19:16.300+0300", "friendly": "21.03.2021 17:19", "epochMillis": 1616336356300 }, "breached": false, "goalDuration": { "millis": 86400000, "friendly": "24h" }, "elapsedTime": { "millis": 620053, "friendly": "10m" }, "remainingTime": { "millis": 85779947, "friendly": "23h 49m" } }, { "startTime": { "iso8601": "2021-03-22T15:57:49+0300", "jira": "2021-03-22T15:57:49.056+0300", "friendly": "22.03.2021 15:57", "epochMillis": 1616417869056 }, "stopTime": { "iso8601": "2021-03-22T15:57:54+0300", "jira": "2021-03-22T15:57:54.510+0300", "friendly": "22.03.2021 15:57", "epochMillis": 1616417874510 }, "breached": false, "goalDuration": { "millis": 86400000, "friendly": "24h" }, "elapsedTime": { "millis": 5454, "friendly": "0m" }, "remainingTime": { "millis": 86394546, "friendly": "23h 59m" } }, { "startTime": { "iso8601": "2021-03-22T16:17:44+0300", "jira": "2021-03-22T16:17:44.969+0300", "friendly": "22.03.2021 16:17", "epochMillis": 1616419064969 }, "stopTime": { "iso8601": "2021-03-22T16:17:51+0300", "jira": "2021-03-22T16:17:51.542+0300", "friendly": "22.03.2021 16:17", "epochMillis": 1616419071542 }, "breached": false, "goalDuration": { "millis": 86400000, "friendly": "24h" }, "elapsedTime": { "millis": 6573, "friendly": "0m" }, "remainingTime": { "millis": 86393427, "friendly": "23h 59m" } }, { "startTime": { "iso8601": "2021-03-22T16:17:54+0300", "jira": "2021-03-22T16:17:54.947+0300", "friendly": "22.03.2021 16:17", "epochMillis": 1616419074947 }, "stopTime": { "iso8601": "2021-03-26T12:49:58+0300", "jira": "2021-03-26T12:49:58.038+0300", "friendly": "26.03.2021 12:49", "epochMillis": 1616752198038 }, "breached": true, "goalDuration": { "millis": 86400000, "friendly": "24h" }, "elapsedTime": { "millis": 333123091, "friendly": "92h 32m" }, "remainingTime": { "millis": -246723091, "friendly": "-68h 32m" } }, { "startTime": { "iso8601": "2021-03-26T15:26:02+0300", "jira": "2021-03-26T15:26:02.225+0300", "friendly": "26.03.2021 15:26", "epochMillis": 1616761562225 }, "stopTime": { "iso8601": "2021-03-26T15:44:19+0300", "jira": "2021-03-26T15:44:19.302+0300", "friendly": "26.03.2021 15:44", "epochMillis": 1616762659302 }, "breached": false, "goalDuration": { "millis": 86400000, "friendly": "24h" }, "elapsedTime": { "millis": 1097077, "friendly": "18m" }, "remainingTime": { "millis": 85302923, "friendly": "23h 41m" } } ] },