diff --git a/CustomAnalytics/PVA_Analytics_Export.json b/CustomAnalytics/PVA_Analytics_Export.json deleted file mode 100644 index 0bbef3c5..00000000 --- a/CustomAnalytics/PVA_Analytics_Export.json +++ /dev/null @@ -1,497 +0,0 @@ -{ - "name": "PVA_Analytics_Export", - "description": "", - "version": "1.0", - "culture": "en-US", - "modifiedTime": "2021-03-17T15:53:39.3636332+00:00", - "pbi:mashup": { - "fastCombine": false, - "allowNativeQueries": false, - "queriesMetadata": { - "botcomponent": { - "queryId": "d1c02c27-4fc7-47e3-a623-155fb9c6152d", - "queryName": "botcomponent", - "loadEnabled": true - }, - "bot": { - "queryId": "8dc931c2-0ac3-4755-ae25-61caf7c91d10", - "queryName": "bot", - "loadEnabled": true - }, - "conversationtranscript": { - "queryId": "48645ace-1a69-4f7b-b342-b0beaddf201b", - "queryName": "conversationtranscript", - "loadEnabled": true - } - }, - "document": "section Section1;\r\nshared botcomponent = let\r\n Source = Cds.Entities(\"**Your server url here**\", null),\r\n #\"Navigation 1\" = Source{[Group = \"entities\"]}[Data],\r\n #\"Navigation 2\" = #\"Navigation 1\"{[EntitySetName = \"botcomponents\"]}[Data]\r\nin\r\n #\"Navigation 2\";\r\nshared bot = let\r\n Source = Cds.Entities(\"**Your server url here**\", null),\r\n #\"Navigation 1\" = Source{[Group = \"entities\"]}[Data],\r\n #\"Navigation 2\" = #\"Navigation 1\"{[EntitySetName = \"bots\"]}[Data]\r\nin\r\n #\"Navigation 2\";\r\nshared conversationtranscript = let\r\n Source = Cds.Entities(\"**Your server url here**\", null),\r\n #\"Navigation 1\" = Source{[Group = \"entities\"]}[Data],\r\n #\"Navigation 2\" = #\"Navigation 1\"{[EntitySetName = \"conversationtranscripts\"]}[Data]\r\nin\r\n #\"Navigation 2\";\r\n" - }, - "annotations": [ - { - "name": "pbi:QueryGroups", - "value": "[]" - } - ], - "entities": [ - { - "$type": "LocalEntity", - "name": "botcomponent", - "description": "", - "pbi:refreshPolicy": { - "$type": "FullRefreshPolicy", - "location": "botcomponent.csv" - }, - "attributes": [ - { - "name": "botcomponentid", - "dataType": "string" - }, - { - "name": "category", - "dataType": "string" - }, - { - "name": "componentidunique", - "dataType": "string" - }, - { - "name": "componentstate", - "dataType": "int64" - }, - { - "name": "componentstate_display", - "dataType": "string" - }, - { - "name": "componenttype", - "dataType": "int64" - }, - { - "name": "componenttype_display", - "dataType": "string" - }, - { - "name": "content", - "dataType": "string" - }, - { - "name": "createdby", - "dataType": "string" - }, - { - "name": "createdon", - "dataType": "dateTimeOffset" - }, - { - "name": "createdonbehalfby", - "dataType": "string" - }, - { - "name": "data", - "dataType": "string" - }, - { - "name": "description", - "dataType": "string" - }, - { - "name": "importsequencenumber", - "dataType": "int64" - }, - { - "name": "ismanaged", - "dataType": "boolean" - }, - { - "name": "language", - "dataType": "int64" - }, - { - "name": "language_display", - "dataType": "string" - }, - { - "name": "modifiedby", - "dataType": "string" - }, - { - "name": "modifiedon", - "dataType": "dateTimeOffset" - }, - { - "name": "modifiedonbehalfby", - "dataType": "string" - }, - { - "name": "name", - "dataType": "string" - }, - { - "name": "overriddencreatedon", - "dataType": "dateTimeOffset" - }, - { - "name": "overwritetime", - "dataType": "dateTimeOffset" - }, - { - "name": "ownerid", - "dataType": "string" - }, - { - "name": "owningbusinessunit", - "dataType": "string" - }, - { - "name": "owningteam", - "dataType": "string" - }, - { - "name": "owninguser", - "dataType": "string" - }, - { - "name": "parentbotcomponentid", - "dataType": "string" - }, - { - "name": "schemaname", - "dataType": "string" - }, - { - "name": "solutionid", - "dataType": "string" - }, - { - "name": "statecode", - "dataType": "int64" - }, - { - "name": "statecode_display", - "dataType": "string" - }, - { - "name": "statuscode", - "dataType": "int64" - }, - { - "name": "statuscode_display", - "dataType": "string" - }, - { - "name": "timezoneruleversionnumber", - "dataType": "int64" - }, - { - "name": "utcconversiontimezonecode", - "dataType": "int64" - }, - { - "name": "versionnumber", - "dataType": "int64" - } - ], - "partitions": [] - }, - { - "$type": "LocalEntity", - "name": "bot", - "description": "", - "pbi:refreshPolicy": { - "$type": "FullRefreshPolicy", - "location": "bot.csv" - }, - "attributes": [ - { - "name": "accesscontrolpolicy", - "dataType": "int64" - }, - { - "name": "accesscontrolpolicy_display", - "dataType": "string" - }, - { - "name": "applicationmanifestinformation", - "dataType": "string" - }, - { - "name": "authenticationmode", - "dataType": "int64" - }, - { - "name": "authenticationmode_display", - "dataType": "string" - }, - { - "name": "authenticationtrigger", - "dataType": "int64" - }, - { - "name": "authenticationtrigger_display", - "dataType": "string" - }, - { - "name": "authorizedsecuritygroupids", - "dataType": "string" - }, - { - "name": "botid", - "dataType": "string" - }, - { - "name": "componentidunique", - "dataType": "string" - }, - { - "name": "componentstate", - "dataType": "int64" - }, - { - "name": "componentstate_display", - "dataType": "string" - }, - { - "name": "configuration", - "dataType": "string" - }, - { - "name": "createdby", - "dataType": "string" - }, - { - "name": "createdon", - "dataType": "dateTimeOffset" - }, - { - "name": "createdonbehalfby", - "dataType": "string" - }, - { - "name": "iconbase64", - "dataType": "string" - }, - { - "name": "importsequencenumber", - "dataType": "int64" - }, - { - "name": "ismanaged", - "dataType": "boolean" - }, - { - "name": "language", - "dataType": "int64" - }, - { - "name": "language_display", - "dataType": "string" - }, - { - "name": "modifiedby", - "dataType": "string" - }, - { - "name": "modifiedon", - "dataType": "dateTimeOffset" - }, - { - "name": "modifiedonbehalfby", - "dataType": "string" - }, - { - "name": "name", - "dataType": "string" - }, - { - "name": "overriddencreatedon", - "dataType": "dateTimeOffset" - }, - { - "name": "overwritetime", - "dataType": "dateTimeOffset" - }, - { - "name": "ownerid", - "dataType": "string" - }, - { - "name": "owningbusinessunit", - "dataType": "string" - }, - { - "name": "owningteam", - "dataType": "string" - }, - { - "name": "owninguser", - "dataType": "string" - }, - { - "name": "publishedby", - "dataType": "string" - }, - { - "name": "publishedon", - "dataType": "dateTimeOffset" - }, - { - "name": "schemaname", - "dataType": "string" - }, - { - "name": "solutionid", - "dataType": "string" - }, - { - "name": "statecode", - "dataType": "int64" - }, - { - "name": "statecode_display", - "dataType": "string" - }, - { - "name": "statuscode", - "dataType": "int64" - }, - { - "name": "statuscode_display", - "dataType": "string" - }, - { - "name": "timezoneruleversionnumber", - "dataType": "int64" - }, - { - "name": "utcconversiontimezonecode", - "dataType": "int64" - }, - { - "name": "versionnumber", - "dataType": "int64" - } - ], - "partitions": [] - }, - { - "$type": "LocalEntity", - "name": "conversationtranscript", - "description": "", - "pbi:refreshPolicy": { - "$type": "FullRefreshPolicy", - "location": "conversationtranscript.csv" - }, - "attributes": [ - { - "name": "bot_conversationtranscriptid", - "dataType": "string" - }, - { - "name": "content", - "dataType": "string" - }, - { - "name": "conversationstarttime", - "dataType": "dateTimeOffset" - }, - { - "name": "conversationtranscriptid", - "dataType": "string" - }, - { - "name": "createdby", - "dataType": "string" - }, - { - "name": "createdon", - "dataType": "dateTimeOffset" - }, - { - "name": "createdonbehalfby", - "dataType": "string" - }, - { - "name": "importsequencenumber", - "dataType": "int64" - }, - { - "name": "metadata", - "dataType": "string" - }, - { - "name": "modifiedby", - "dataType": "string" - }, - { - "name": "modifiedon", - "dataType": "dateTimeOffset" - }, - { - "name": "modifiedonbehalfby", - "dataType": "string" - }, - { - "name": "name", - "dataType": "string" - }, - { - "name": "overriddencreatedon", - "dataType": "dateTimeOffset" - }, - { - "name": "ownerid", - "dataType": "string" - }, - { - "name": "owningbusinessunit", - "dataType": "string" - }, - { - "name": "owningteam", - "dataType": "string" - }, - { - "name": "owninguser", - "dataType": "string" - }, - { - "name": "schematype", - "dataType": "string" - }, - { - "name": "schemaversion", - "dataType": "string" - }, - { - "name": "statecode", - "dataType": "int64" - }, - { - "name": "statecode_display", - "dataType": "string" - }, - { - "name": "statuscode", - "dataType": "int64" - }, - { - "name": "statuscode_display", - "dataType": "string" - }, - { - "name": "timezoneruleversionnumber", - "dataType": "int64" - }, - { - "name": "utcconversiontimezonecode", - "dataType": "int64" - }, - { - "name": "versionnumber", - "dataType": "int64" - } - ], - "partitions": [] - } - ] -} \ No newline at end of file diff --git a/CustomAnalytics/PVA_Dashboard.pbit b/CustomAnalytics/PVA_Dashboard.pbit index 878edd88..81973b16 100644 Binary files a/CustomAnalytics/PVA_Dashboard.pbit and b/CustomAnalytics/PVA_Dashboard.pbit differ diff --git a/CustomAnalytics/readme.md b/CustomAnalytics/readme.md index 33ed58ab..4464c9b0 100644 --- a/CustomAnalytics/readme.md +++ b/CustomAnalytics/readme.md @@ -7,14 +7,13 @@ This solution allows customers to create a Power BI dashboard for their Power Vi ## Solution components - Microsoft Dataverse -- Microsoft Power BI DataFlows - Microsoft Power BI Desktop -- Chat Transcripts control for Power BI - available at +- Chat Transcripts control for Power BI - available at - many thanks to Mick Vleeshouwer +- (Optional) Microsoft Power BI DataFlows - (Optional) Azure Data Lake Storage v2 ## Solution files -- PVA_Analytics_Export.json - this is the template for a PowerBI DataFlow - PVA_Dashboard.pbit - Power BI template file ## Installation @@ -27,32 +26,40 @@ This solution allows customers to create a Power BI dashboard for their Power Vi ### Installation steps -1. **Edit the DataFlow template** - 1. [Find your Dataverse environment URL](https://docs.microsoft.com/en-us/powerapps/maker/data-platform/data-platform-powerbi-connector#find-your-dataverse-environment-url), the URL will be in the format: https://yourenvironmentid.crm.dynamics.com/. Make sure you remove the trailing / from the URL. - 2. Download the file [PVA Analytics_Export.json](PVA_Analytics_Export.json?plain=1) and open it in a text editor, e.g. Visual Studio Code. - 3. Perform a find and replace on the file - swapping the placeholder `**Your server url here**` with your Dataverse environment URL. - -2. **Create the DataFlow from the template** - 1. Log in to Power BI at - 2. Select the Workspace you wish to deploy the DataFlow to or create a new workspace. Please note that you cannot use 'My Workspace' for this purpose. - 3. Select New > DataFlow - 4. Select Import Model - 5. Select the edited file 'PVA Analytics_Export.json'. Your DataFlow job should now be ready - test refreshing the data. - (the template defaults to 'PVA_Analytics' as DataFlow name). - 6. If Power BI prompts for credentials, go to Settings -> Data source credentials and select organizational account. You can now login with an Azure Active Directory account that has access to the Dataverse environment. - 7. If you want to refresh the content periodically, go to Settings -> Scheduled refresh and select the preferred period. - -3. **Create your Power BI report** - 1. Download the file [PVA_Dashboard.pbit](PVA_Dashboard.pbit?plain=1) - 2. Enter the parameters you are prompted for. These are: - 1. The name of the Power BI workspace - 2. The name of the DataFlow you created - 3. The report should pull in the data and render it - 4. You can now [publish the report from Power BI Desktop](https://docs.microsoft.com/en-us/power-bi/create-reports/desktop-upload-desktop-files) so that other users can access it. - -## TBD Connecting Azure Data Lake Storage for data archival - -Using Azure Data Lake Storage v2, DataVerse can archive the data used in this report, to support datasets greater than 30 days. This pattern is in developement. +1. Create your PowerBI report + 1. Open the file PVA_Dashboard.pbit + 2. Enter the parameter you are prompted for. This is: + 1. The URI of you Dataverse instance (e.g. mydataverse.crm.dynamics.com - note the removal of 'https://' and the trailing slash) + 3. The report should pull through the data and render it + 4. You can now save the report to share through the Power BI portal. + +## Connecting Azure Data Lake Storage for data archival + +Optional - if you wish to store and use telemetry longer than it is stored in your Dataverse instance (default 30 days), you can configure export to Azure Data Lake using Azure Synapse Link. Steps for configuring this are as follows: + +!Important - always test this process on a development environment before applying to your production system. + +1. Set up an Azure Data Lake, and connect to it using Azure Synapse Link. See the steps documented here for details: . +2. Configure the conversationtranscript table for export using Azure Synapse Link + 1. In the Power Apps portal, select Azure Synapse Link - select the link you created in step 1 - Manage tables + 2. Search for 'conversationtranscript' - Save. + 3. Transcipts will now be exported to your Azure Data Lake + +3. Create a new Power BI DataFlow exposing the data stored in Data Lake + 1. Open your Power BI Workspace - New - DataFlow + 2. Select 'Attach a Common Data Model' folder + 3. Browse you Azure Data Lake container, and paste the URL of your 'model.json' file that describes your data. + +4. Add the DataFlow version of conversationtranscipt to your Power BI report + 1. In the Power BI report, select 'Transform Data' to open Power Query + 2. Select Get Data - Power BI DataFlows. Select your new DataFlow + 3. A copy of the conversationtranscript will now be added. + 4. Select the original conversation transcript table in Power Query. In 'Applied Steps' select the top option 'Source' + 5. In the command window, type '= conversationtranscript2' (or the name you have given the new table). + 6. The orignal table will now point to the table coming from the DataFlow. + +5. Refresh the report. +6. Note that managing the data in your DataLake will require additional attention, outside the scope of these steps. ## Using the report @@ -65,10 +72,5 @@ The report is based on what is shared through the Power Virtual Agents portal, b ## Troubleshooting -There are a few places where the pipeline may break - troublshooting can normally isolate the problem using these steps: - -1. Ensure that data is being pulled in to your DataFlow correctly. Open the DataFlow for editing (select 'edit entities'), and on each of the tables, select refresh to ensure that data is being populated. -2. Ensure that your Power BI report is connecting to DataFlows. If an error happens when you first pull in data, select 'Transform data' in the navigation menu to open Power Query - 1. Refresh each table in the 'Raw Data' folder - these correspond to the data in the DataFlow. - 2. If this fails also, test you have permissions to the DataFlow. An easy way to do this is to open the 'bot' query at the top of the query list, and select 'Source' at the top of the 'Applied steps' control. This lists all the DataFlows you have access to. -3. If both of the steps above succeed, but you still have errors, please raise an issue in this repo. +1. Ensure you have permission to access the TDS endpoint in Dataverse. Empty data tables may indicate a permissions problem. +2. Please raise issues in the repo for other problems.