This commit is contained in:
morsh 2017-06-16 11:00:55 +02:00
Родитель 216338084c
Коммит f33470d417
4 изменённых файлов: 1657 добавлений и 44 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -4,7 +4,7 @@ import * as _ from 'lodash';
// The following line is important to keep in that format so it can be rendered into the page
export const config: IDashboardConfig = /*return*/ {
id: 'bot_analytics_dashboard',
name: 'Bot Analytics Dashboard',
name: 'Bot Analytics Basic Dashboard',
icon: "dashboard",
url: "bot_analytics_dashboard",
description: 'Microsoft Bot Framework based analytics',
@ -154,40 +154,6 @@ export const config: IDashboardConfig = /*return*/ {
params: {
table: "customEvents",
queries: {
conversions: {
query: () => `
extend successful=tostring(customDimensions.successful) |
where name in ('MBFEvent.StartTransaction', 'MBFEvent.EndTransaction') |
summarize event_count=count() by name, successful`,
mappings: { successful: (val) => val === 'true',event_count: (val) => val || 0 },
filters: [{ dependency: "selectedChannels",queryProperty: "customDimensions.channel" }],
calculated: (conversions) => {
// Conversion Handling
// ===================
let total, successful;
total = _.find(conversions, { name: 'MBFEvent.StartTransaction' });
successful = _.find(conversions, { name: 'MBFEvent.EndTransaction', successful: true }) || { event_count: 0 };
if (!total) {
return null;
}
// TODO: +5 to enable true numbers in conversions
var displayValues = [
{ label: 'Successful', count: successful.event_count },
{ label: 'Failed', count: total.event_count - successful.event_count + 5 },
];
let conversionRate = (100 * total.event_count / (successful.event_count + 5)).toFixed(1);
return {
"conversions-displayValues": displayValues,
"conversions-rate": conversionRate + '%',
};
}
},
timeline: {
query: (dependencies) => {
var { granularity } = dependencies;
@ -315,6 +281,40 @@ export const config: IDashboardConfig = /*return*/ {
return { "users-value": (users && users.length && users[0].totalUsers) || 0 };
}
},
conversions: {
query: () => `
extend successful=tostring(customDimensions.successful) |
where name in ('MBFEvent.StartTransaction', 'MBFEvent.EndTransaction') |
summarize event_count=count() by name, successful`,
mappings: { successful: (val) => val === 'true',event_count: (val) => val || 0 },
filters: [{ dependency: "selectedChannels",queryProperty: "customDimensions.channel" }],
calculated: (conversions) => {
// Conversion Handling
// ===================
let total, successful;
total = _.find(conversions, { name: 'MBFEvent.StartTransaction' });
successful = _.find(conversions, { name: 'MBFEvent.EndTransaction', successful: true }) || { event_count: 0 };
if (!total) {
return null;
}
// TODO: +5 to enable true numbers in conversions
var displayValues = [
{ label: 'Successful', count: successful.event_count },
{ label: 'Failed', count: total.event_count - successful.event_count + 5 },
];
let conversionRate = (100 * total.event_count / (successful.event_count + 5)).toFixed(1);
return {
"conversions-displayValues": displayValues,
"conversions-rate": conversionRate + '%',
};
}
},
mapActivity: {
query: () => `
where name=='Activity' |
@ -408,6 +408,15 @@ export const config: IDashboardConfig = /*return*/ {
filters: [{ dependency: "selectedChannels",queryProperty: "customDimensions.channel" }],
calculated: results =>
({ retention_avg_messages_per_session: (results && results.length && results[0].avg_sessions) || 0 })
},
retention_top_users: {
query: () => `
where name == "MBFEvent.UserMessage" |
extend userId=substring(tostring(customDimensions.userId), 0, 30), fullUserId=tostring(customDimensions.userId) |
summarize messages=count() by fullUserId, userId |
top 5 by messages
`,
filters: [{ dependency: "selectedChannels",queryProperty: "customDimensions.channel" }]
}
}
}
@ -695,10 +704,46 @@ export const config: IDashboardConfig = /*return*/ {
{
id: "intentsDialog-data",
type: "ApplicationInsights/Query",
dependencies: { intent: "dialog_intentsDialog:intent",queryTimespan: "dialog_intentsDialog:queryspan" },
dependencies: {
intent: "dialog_intentsDialog:intent",
queryTimespan: "dialog_intentsDialog:queryspan",
timespan: "timespan",
granularity: "timespan:granularity"
},
params: {
table: "customEvents",
queries: {
"intent-usage": {
query: ({ intent, granularity }) => `
extend intent=(customDimensions.intent)
| where timestamp > ago(30d) and intent =~ "${intent}"
| summarize intent_count=count() by bin(timestamp, ${granularity})
| order by timestamp
`,
calculated: (timeline, dependencies) => {
// Timeline handling
// =================
let _timeline = [];
let { timespan } = dependencies;
timeline.forEach(row => {
var { timestamp, intent_count } = row;
var timeValue = (new Date(timestamp)).getTime();
_timeline.push({
time: (new Date(timestamp)).toUTCString(),
value: intent_count
});
});
return {
"timeline-graphData": _timeline,
"timeline-values": ["value"],
"timeline-timeFormat": (timespan === "24 hours" ? 'hour' : 'date')
};
}
},
"entities-usage": {
query: ({ intent }) => `
extend conversation=tostring(customDimensions.conversationId),
@ -901,7 +946,7 @@ export const config: IDashboardConfig = /*return*/ {
type: "BarData",
title: "Entity count appearances in intent",
subtitle: "Entity usage and count for the selected intent",
size: { w: 4,h: 8 },
size: { w: 6,h: 8 },
dependencies: { values: "intentsDialog-data:entities-usage",bars: "intentsDialog-data:entities-usage-bars" },
props: { nameKey: "entityType" }
},
@ -914,6 +959,19 @@ export const config: IDashboardConfig = /*return*/ {
cols: [{ header: "Top Utterances",width: "200px",field: "text" },{ header: "Count",field: "count_utterances",type: "number" }]
}
},
{
id: "intent-timeline",
type: "Timeline",
title: "Message Rate",
subtitle: "How many messages were sent per timeframe",
size: { w: 8,h: 8 },
dependencies: {
visible: "modes:messages",
values: "intentsDialog-data:timeline-graphData",
lines: "intentsDialog-data:timeline-values",
timeFormat: "intentsDialog-data:timeline-timeFormat"
}
},
{
id: "conversations-count",
type: "Scorecard",
@ -1048,7 +1106,7 @@ export const config: IDashboardConfig = /*return*/ {
actions: {
openMessagesDialog: {
action: "dialog:messages",
params: { title: "args:id",conversation: "args:conversation",queryspan: "timespan:queryTimespan" }
params: { title: "args:id",conversation: "args:conversation",queryspan: "timespan:queryTimespan",intent: "::" }
}
}
},
@ -1070,7 +1128,7 @@ export const config: IDashboardConfig = /*return*/ {
actions: {
openMessagesDialog: {
action: "dialog:messages",
params: { title: "args:id",conversation: "args:conversation",queryspan: "timespan:queryTimespan" }
params: { title: "args:id",conversation: "args:conversation",queryspan: "timespan:queryTimespan",intent: "::" }
}
}
}
@ -1300,7 +1358,7 @@ export const config: IDashboardConfig = /*return*/ {
{
id: "retention-scores",
type: "Scorecard",
size: { w: 12,h: 3 },
size: { w: 6,h: 3 },
dependencies: {
card_msgs_icon: "::chat",
card_msgs_value: "ai:retention_total_incoming_messages",
@ -1326,9 +1384,10 @@ export const config: IDashboardConfig = /*return*/ {
id: "user-retention-table",
type: "Table",
title: "User Retention",
size: { w: 12,h: 9 },
size: { w: 3,h: 9 },
dependencies: { values: "retention" },
props: {
compact: true,
cols: [
{ header: "Time Span",field: "timespan" },
{ header: "Retention",field: "retention" },
@ -1336,6 +1395,76 @@ export const config: IDashboardConfig = /*return*/ {
{ header: "Unique Users",field: "unique" }
]
}
},
{
id: "top-users-table",
type: "Table",
title: "Top Users",
size: { w: 3,h: 9 },
dependencies: { values: "ai:retention_top_users" },
props: {
compact: true,
cols: [
{ header: "User Id",field: "userId" },
{ header: "Messages",field: "messages" },
{ type: "button",value: "chat",click: "openMessagesDialog" }
]
},
actions: {
openMessagesDialog: {
action: "dialog:userConversations",
params: { title: "args:userId",userId: "args:fullUserId",queryspan: "timespan:queryTimespan" }
}
}
}
]
},
{
id: "userConversations",
width: "60%",
params: ["title","userId","queryspan"],
dataSources: [
{
id: "user-conversations-data",
type: "ApplicationInsights/Query",
dependencies: { userId: "dialog_userConversations:userId",queryTimespan: "dialog_userConversations:queryspan" },
params: {
query: ({ userId }) => `
customEvents
| extend conversation=tostring(customDimensions.conversationId), userId=tostring(customDimensions.userId)
| where name=='MBFEvent.UserMessage' and userId == '${userId}'
| summarize count=count(), maxTimestamp=max(timestamp) by conversation
| order by maxTimestamp`,
mappings: { id: (val, row, idx) => `Conversation ${idx}` }
}
}
],
elements: [
{
id: "user-conversations-list",
type: "Table",
title: "Conversations",
size: { w: 12,h: 16 },
dependencies: { values: "user-conversations-data" },
props: {
cols: [
{ header: "Conversation Id",field: "id" },
{ header: "Last Message",field: "maxTimestamp",type: "time",format: "MMM-DD HH:mm:ss" },
{ header: "Count",field: "count" },
{ type: "button",value: "chat",click: "openMessagesDialog" }
]
},
actions: {
openMessagesDialog: {
action: "dialog:messages",
params: {
title: "args:id",
conversation: "args:conversation",
intent: "dialog_intentConversations:intent",
queryspan: "timespan:queryTimespan"
}
}
}
}
]
}

Просмотреть файл

@ -183,7 +183,7 @@ export default class Home extends React.Component<any, IHomeState> {
return null;
}
let templateCards = templates.map((temp, index) => (
let createCard = (temp, index) => (
<div key={index} className="md-cell" style={styles.card}>
<Card className="md-block-centered" key={index} >
<Media>
@ -202,10 +202,22 @@ export default class Home extends React.Component<any, IHomeState> {
</CardActions>
</Card>
</div>
));
);
// Finding featured
let featuredCards = templates
.filter(temp => temp.id === 'bot_analytics_dashboard' || temp.id === 'bot_analytics_inst')
.map(createCard);
let templateCards = templates.map(createCard);
return (
<div>
<h1>Bot Analytics</h1>
<div className="md-grid">
{featuredCards}
</div>
<h1>All Dashboards</h1>
<div className="md-grid">
{templateCards}
</div>

Просмотреть файл

@ -146,7 +146,7 @@ export default class Table extends GenericComponent<ITableProps, ITableState> {
{
cols.map((col, ci) => (
<TableColumn key={ci} className={this.fixClassName(col.field || col.value)}>
<span className="indicator"></span>{renderColumn(col, value)}
<span className="indicator" />{renderColumn(col, value)}
</TableColumn>
))
}