Forum Discussion

alexey-denisov's avatar
alexey-denisov
Frequent Visitor
5 years ago

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

    • alexey-denisov's avatar
      alexey-denisov
      Frequent 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 format

       

       in 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"
      }
      }
      ]
      },