diff --git a/plugins/AutoTask/v1/custom_types.json b/plugins/AutoTask/v1/custom_types.json index 0aba596..e95f453 100644 --- a/plugins/AutoTask/v1/custom_types.json +++ b/plugins/AutoTask/v1/custom_types.json @@ -33,5 +33,19 @@ "icon": "file-text", "singular": "Contract", "plural": "Contracts" + }, + { + "name": "AutotaskTicketStatus", + "sourceType": "autotask-ticket-status", + "icon": "circle-dot", + "singular": "Ticket Status", + "plural": "Ticket Statuses" + }, + { + "name": "AutotaskTicketPriority", + "sourceType": "autotask-ticket-priority", + "icon": "arrow-up-circle", + "singular": "Ticket Priority", + "plural": "Ticket Priorities" } ] diff --git a/plugins/AutoTask/v1/dataStreams/scripts/ticketPriorities.js b/plugins/AutoTask/v1/dataStreams/scripts/ticketPriorities.js new file mode 100644 index 0000000..ce7c789 --- /dev/null +++ b/plugins/AutoTask/v1/dataStreams/scripts/ticketPriorities.js @@ -0,0 +1,6 @@ +const priorityField = data.fields.find(f => f.name === "priority"); +const values = priorityField ? priorityField.picklistValues : []; +result = values + .filter(pv => pv.isActive) + .sort((a, b) => a.sortOrder - b.sortOrder) + .map(pv => ({ id: String(pv.value), name: pv.label })); diff --git a/plugins/AutoTask/v1/dataStreams/scripts/ticketStatuses.js b/plugins/AutoTask/v1/dataStreams/scripts/ticketStatuses.js new file mode 100644 index 0000000..e63b3d5 --- /dev/null +++ b/plugins/AutoTask/v1/dataStreams/scripts/ticketStatuses.js @@ -0,0 +1,6 @@ +const statusField = data.fields.find(f => f.name === "status"); +const values = statusField ? statusField.picklistValues : []; +result = values + .filter(pv => pv.isActive) + .sort((a, b) => a.sortOrder - b.sortOrder) + .map(pv => ({ id: String(pv.value), name: pv.label })); diff --git a/plugins/AutoTask/v1/dataStreams/ticketPriorities.json b/plugins/AutoTask/v1/dataStreams/ticketPriorities.json new file mode 100644 index 0000000..f4e3ef7 --- /dev/null +++ b/plugins/AutoTask/v1/dataStreams/ticketPriorities.json @@ -0,0 +1,19 @@ +{ + "name": "ticketPriorities", + "displayName": "Ticket Priorities", + "description": "All ticket priorities from AutoTask", + "tags": ["Tickets"], + "baseDataSourceName": "httpRequestUnscoped", + "visibility": { "type": "hidden" }, + "timeframes": false, + "config": { + "httpMethod": "get", + "endpointPath": "atservicesrest/v1.0/Tickets/entityInformation/fields", + "postRequestScript": "ticketPriorities.js", + "paging": { "mode": "none" } + }, + "metadata": [ + { "name": "id", "displayName": "Priority ID", "shape": "string", "role": "value", "visible": false }, + { "name": "name", "displayName": "Priority Name", "shape": "string", "role": "label" } + ] +} diff --git a/plugins/AutoTask/v1/dataStreams/ticketStatuses.json b/plugins/AutoTask/v1/dataStreams/ticketStatuses.json new file mode 100644 index 0000000..ed2944e --- /dev/null +++ b/plugins/AutoTask/v1/dataStreams/ticketStatuses.json @@ -0,0 +1,19 @@ +{ + "name": "ticketStatuses", + "displayName": "Ticket Statuses", + "description": "All active ticket statuses from AutoTask, including custom statuses", + "tags": ["Tickets"], + "baseDataSourceName": "httpRequestUnscoped", + "visibility": { "type": "hidden" }, + "timeframes": false, + "config": { + "httpMethod": "get", + "endpointPath": "atservicesrest/v1.0/Tickets/entityInformation/fields", + "postRequestScript": "ticketStatuses.js", + "paging": { "mode": "none" } + }, + "metadata": [ + { "name": "id", "displayName": "Status ID", "shape": "string", "role": "value", "visible": false }, + { "name": "name", "displayName": "Status Name", "shape": "string", "role": "label" } + ] +} diff --git a/plugins/AutoTask/v1/dataStreams/tickets.json b/plugins/AutoTask/v1/dataStreams/tickets.json index 17766c6..7fbcc2d 100644 --- a/plugins/AutoTask/v1/dataStreams/tickets.json +++ b/plugins/AutoTask/v1/dataStreams/tickets.json @@ -11,7 +11,7 @@ "config": { "httpMethod": "get", "expandInnerObjects": true, - "endpointPath": "atservicesrest/v1.0/Tickets/query?search={\"MaxRecords\":500,\"filter\":[{\"op\":\"in\",\"field\":\"status\",\"value\":[{{statusFilter}}]},{\"op\":\"in\",\"field\":\"priority\",\"value\":[{{priorityFilter}}]},{\"op\":\"gte\",\"field\":\"lastActivityDate\",\"value\":\"{{timeframe.start}}\"},{\"op\":\"lte\",\"field\":\"lastActivityDate\",\"value\":\"{{timeframe.end}}\"}]}", + "endpointPath": "atservicesrest/v1.0/Tickets/query?search={\"MaxRecords\":500,\"filter\":[{{statusFilter ? '{\"op\":\"in\",\"field\":\"status\",\"value\":[' + statusFilter + ']},' : ''}}{{priorityFilter ? '{\"op\":\"in\",\"field\":\"priority\",\"value\":[' + priorityFilter + ']},' : ''}}{\"op\":\"gte\",\"field\":\"lastActivityDate\",\"value\":\"{{timeframe.start}}\"},{\"op\":\"lte\",\"field\":\"lastActivityDate\",\"value\":\"{{timeframe.end}}\"}]}", "postRequestScript": "tickets.js", "pathToData": "items", "paging": { @@ -28,28 +28,33 @@ { "name": "id", "displayName": "Ticket ID", "shape": "string", "visible": false }, { "name": "title", "displayName": "Title" }, { "name": "description", "displayName": "Description", "visible": false }, + { "name": "status", "displayName": "Status (Raw)", "sourceType": "autotask-ticket-status", "shape": "string", "visible": false }, { "name": "statusName", "displayName": "Status", - "visible": true, + "sourceId": "status", + "objectPropertyPath": "name" + }, + { + "name": "statusHealth", + "displayName": "Status Health", "computed": true, - "valueExpression": "{{ $['status'] == 1 ? 'New' : $['status'] == 5 ? 'Complete' : $['status'] == 8 ? 'In Progress' : $['status'] == 9 ? 'Waiting Customer' : $['status'] == 10 ? 'Waiting Materials' : $['status'] == 11 ? 'Waiting Vendor' : $['status'] == 12 ? 'Escalate' : $['status'] == 13 ? 'Waiting Approval' : 'Unknown' }}", + "valueExpression": "{{ $['statusName'] }}", "shape": ["state", { "map": { "success": ["Complete"], "error": ["Escalate"], - "warning": ["New", "In Progress"], - "unknown": ["Waiting Customer", "Waiting Materials", "Waiting Vendor", "Waiting Approval", "Unknown"] + "warning": ["New", "In Progress", "Waiting Customer", "Waiting Materials", "Waiting Vendor", "Waiting for Vendor", "Waiting Approval"] } }] }, { "name": "priorityName", "displayName": "Priority", - "computed": true, - "valueExpression": "{{ $['priority'] == 1 ? 'Critical' : $['priority'] == 2 ? 'High' : $['priority'] == 3 ? 'Medium' : $['priority'] == 4 ? 'Low' : 'Unknown' }}" + "sourceId": "priority", + "objectPropertyPath": "name" }, - { "name": "priority", "displayName": "Priority (Raw)", "shape": ["number", { "decimalPlaces": 0 }], "visible": false }, + { "name": "priority", "displayName": "Priority (Raw)", "sourceType": "autotask-ticket-priority", "shape": "string", "visible": false }, { "name": "companyID", "sourceType": "autotask-company", "shape": "string", "visible": false }, { "name": "companyName", "displayName": "Company", "sourceId": "companyID", "objectPropertyPath": "name" }, { "name": "contactID", "sourceType": "autotask-contact", "shape": "string", "visible": false }, @@ -137,22 +142,11 @@ "label": "Status", "allowCustomValues": true, "isMulti": true, - "defaultValue": "1,5,8,9,10,11,12,13", "data": { - "source": "fixed", - "values": [ - { "value": "1,5,8,9,10,11,12,13", "label": "All Statuses" }, - { "value": "1", "label": "New" }, - { "value": "8", "label": "In Progress" }, - { "value": "9", "label": "Waiting Customer" }, - { "value": "10", "label": "Waiting Materials" }, - { "value": "11", "label": "Waiting Vendor" }, - { "value": "13", "label": "Waiting Approval" }, - { "value": "12", "label": "Escalate" }, - { "value": "5", "label": "Complete" } - ] - }, - "validation": { "required": true } + "source": "dataStream", + "dataStreamName": "ticketStatuses", + "dataSourceConfig": {} + } }, { "name": "priorityFilter", @@ -160,18 +154,11 @@ "label": "Priority", "allowCustomValues": true, "isMulti": true, - "defaultValue": "1,2,3,4", "data": { - "source": "fixed", - "values": [ - { "value": "1,2,3,4", "label": "All Priorities" }, - { "value": "1", "label": "Critical" }, - { "value": "2", "label": "High" }, - { "value": "3", "label": "Medium" }, - { "value": "4", "label": "Low" } - ] - }, - "validation": { "required": true } + "source": "dataStream", + "dataStreamName": "ticketPriorities", + "dataSourceConfig": {} + } } ] } diff --git a/plugins/AutoTask/v1/defaultContent/scopes.json b/plugins/AutoTask/v1/defaultContent/scopes.json new file mode 100644 index 0000000..50b5926 --- /dev/null +++ b/plugins/AutoTask/v1/defaultContent/scopes.json @@ -0,0 +1,17 @@ +[ + { + "name": "Companies", + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["autotask-company"] + } + }, + "variable": { + "name": "Company", + "allowMultipleSelection": true, + "default": "none", + "type": "object" + } + } +] diff --git a/plugins/AutoTask/v1/defaultContent/tickets.dash.json b/plugins/AutoTask/v1/defaultContent/tickets.dash.json index 26f271a..e113dbd 100644 --- a/plugins/AutoTask/v1/defaultContent/tickets.dash.json +++ b/plugins/AutoTask/v1/defaultContent/tickets.dash.json @@ -1,8 +1,12 @@ { "name": "Tickets Overview", "schemaVersion": "1.4", + "timeframe": "last7days", + "variables": ["{{variables.[Company]}}"], "dashboard": { "_type": "layout/grid", + "columns": 4, + "version": 1, "contents": [ { "static": false, @@ -14,8 +18,18 @@ "i": "35674a0b-dd87-4845-a083-33fac61b20a8", "z": 0, "config": { - "timeframe": "last7days", + "_type": "tile/data-stream", + "title": "Overdue Tickets", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Company]}}"], + "scope": { + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" + }, "dataStream": { + "id": "{{dataStreams.tickets}}", "name": "tickets", "filter": { "multiOperation": "and", @@ -28,49 +42,13 @@ "value": "1" }, { - "column": "statusName", + "column": "statusHealth", "operation": "notequals", "value": "success" } ] - }, - "id": "{{dataStreams.tickets}}" - }, - "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).limit(500)", - "bindings": {}, - "queryDetail": {} - }, - "_type": "tile/data-stream", - "description": "", - "monitor": { - "tileRollsUp": true, - "monitorType": "threshold", - "condition": { - "columns": [], - "logic": { - "if": [ - { - ">": [ - { - "var": "count" - }, - 0 - ] - }, - "error" - ] - } - }, - "_type": "simple", - "aggregation": "count", - "groupBy": "__group_by_none__", - "frequency": 720 + } }, - "activePluginConfigIds": [ - "{{configId}}" - ], - "title": "Overdue Tickets", "visualisation": { "type": "data-stream-scalar", "config": { @@ -94,32 +72,30 @@ "i": "99af9bf5-ac61-4546-a13f-d2cd838fd3b6", "z": 0, "config": { - "timeframe": "last7days", + "_type": "tile/data-stream", + "title": "Open Tickets", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Company]}}"], + "scope": { + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" + }, "dataStream": { + "id": "{{dataStreams.tickets}}", "name": "tickets", "filter": { "multiOperation": "and", "filters": [ { - "column": "status", + "column": "statusName", "operation": "notequals", - "value": "5" + "value": "Complete" } ] - }, - "id": "{{dataStreams.tickets}}" - }, - "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).limit(500)", - "bindings": {}, - "queryDetail": {} + } }, - "_type": "tile/data-stream", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "title": "Open Tickets", "visualisation": { "type": "data-stream-scalar", "config": { @@ -143,54 +119,51 @@ "i": "353ede63-eccf-433d-91c0-5f6a2dc33af5", "z": 0, "config": { + "_type": "tile/data-stream", + "title": "Avg First Response Time", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Company]}}"], + "scope": { + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" + }, "dataStream": { + "id": "datastream-sql", "dataSourceConfig": { "version": "2.0", "tables": [ { + "tableName": "dataset1", "config": { "timeframe": "last7days", - "activePluginConfigIds": [ - "{{configId}}" - ], + "activePluginConfigIds": ["{{configId}}"], "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).limit(500)", - "bindings": {}, - "queryDetail": {} + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" }, "dataStream": { + "id": "{{dataStreams.tickets}}", "name": "tickets", "filter": { "multiOperation": "and", "filters": [ { - "column": "statusName", + "column": "statusHealth", "operation": "equals", "value": "success" } ] - }, - "id": "{{dataStreams.tickets}}" + } } - }, - "tableName": "dataset1" + } } ], "sql": "SELECT\r\n ROUND( AVG(DATE_DIFF('hour', \"createDate\",\"firstResponseDateTime\")),2) AS \"avg_hours_difference\"\r\nFROM\r\n \"dataset1\"" - }, - "id": "datastream-sql" - }, - "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).limit(500)", - "bindings": {}, - "queryDetail": {} + } }, - "_type": "tile/data-stream", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "title": "Avg First Response Time", "visualisation": { "type": "data-stream-scalar", "config": { @@ -213,61 +186,58 @@ "i": "113d7b96-e608-4dca-82f8-fa93ff880528", "z": 0, "config": { + "_type": "tile/data-stream", + "title": "Avg Time to Resolution", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Company]}}"], + "scope": { + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" + }, "dataStream": { + "id": "datastream-sql", "dataSourceConfig": { "version": "2.0", "tables": [ { + "tableName": "dataset1", "config": { "timeframe": "last7days", - "activePluginConfigIds": [ - "{{configId}}" - ], + "activePluginConfigIds": ["{{configId}}"], "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).limit(500)", - "bindings": {}, - "queryDetail": {} + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" }, "dataStream": { + "id": "{{dataStreams.tickets}}", "name": "tickets", "filter": { "multiOperation": "and", "filters": [ { - "column": "statusName", + "column": "statusHealth", "operation": "equals", "value": "success" } ] - }, - "id": "{{dataStreams.tickets}}" + } } - }, - "tableName": "dataset1" + } } ], "sql": "WITH\r\n \"resolution_times\" AS (\r\n SELECT\r\n CAST(\r\n EXTRACT (\r\n EPOCH\r\n FROM\r\n \"resolvedDateTime\" - \"createDate\"\r\n ) AS INTEGER\r\n ) / 3600 AS \"resolution_time_hours\"\r\n FROM\r\n \"dataset1\"\r\n )\r\nSELECT\r\n ROUND(AVG(\"resolution_time_hours\"),2) AS \"avg_resolution_hours\"\r\nFROM\r\n \"resolution_times\"" - }, - "id": "datastream-sql" - }, - "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).limit(500)", - "bindings": {}, - "queryDetail": {} + } }, - "_type": "tile/data-stream", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "title": "Avg Time to Resolution", "visualisation": { "type": "data-stream-scalar", "config": { "data-stream-scalar": { + "value": "avg_resolution_hours", "comparisonColumn": "none", - "label": "Hours", - "value": "avg_resolution_hours" + "label": "Hours" } } } @@ -283,13 +253,19 @@ "i": "73f1150f-0a49-49be-974f-f2da0e33a0b5", "z": 0, "config": { - "timeframe": "last7days", + "_type": "tile/data-stream", + "title": "Tickets per Assigned Resource", + "description": "Open tickets", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Company]}}"], + "scope": { + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" + }, "dataStream": { + "id": "{{dataStreams.tickets}}", "name": "tickets", - "dataSourceConfig": { - "priorityFilter": "1,2,3,4", - "statusFilter": "1,5,8,9,10,11,12,13" - }, "filter": { "multiOperation": "and", "filters": [ @@ -299,32 +275,11 @@ } ] }, - "id": "{{dataStreams.tickets}}", "group": { - "by": [ - [ - "assignedResourceName", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "count" - } - ] + "by": [["assignedResourceName", "uniqueValues"]], + "aggregate": [{ "type": "count" }] } }, - "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).or(__.has(\"sourceType\", \"autotask-company\")).limit(500)", - "bindings": {}, - "queryDetail": {} - }, - "_type": "tile/data-stream", - "description": "Open tickets", - "activePluginConfigIds": [ - "{{configId}}" - ], - "title": "Tickets per Assigned Resource", "visualisation": { "type": "data-stream-table", "config": { @@ -349,12 +304,21 @@ "i": "15c45143-76f4-4d64-93e1-5e270dd78396", "z": 0, "config": { - "timeframe": "last7days", + "_type": "tile/data-stream", + "title": "Tickets Closed per Resource", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "variables": ["{{variables.[Company]}}"], + "scope": { + "scope": "{{scopes.[Companies]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Company]}}" + }, "dataStream": { + "id": "{{dataStreams.tickets}}", "name": "tickets", "dataSourceConfig": { - "priorityFilter": "1,2,3,4", - "statusFilter": "1,5,8,9,10,11,12,13" + "statusFilter": "5" }, "filter": { "multiOperation": "and", @@ -365,32 +329,11 @@ } ] }, - "id": "{{dataStreams.tickets}}", "group": { - "by": [ - [ - "assignedResourceName", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "count" - } - ] + "by": [["assignedResourceName", "uniqueValues"]], + "aggregate": [{ "type": "count" }] } }, - "scope": { - "query": "g.V().order().by('__name').hasNot('__canonicalType').has(\"__configId\", within(\"{{configId}}\")).or(__.has(\"sourceType\", \"autotask-company\")).limit(500)", - "bindings": {}, - "queryDetail": {} - }, - "_type": "tile/data-stream", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "title": "Tickets Closed per Resource", "visualisation": { "type": "data-stream-table", "config": { @@ -405,10 +348,6 @@ } } } - ], - "version": 83, - "columns": 4 - }, - "path": "tickets", - "folderPath": [] + ] + } } diff --git a/plugins/AutoTask/v1/indexDefinitions/default.json b/plugins/AutoTask/v1/indexDefinitions/default.json index d29a6bf..62ec5a4 100644 --- a/plugins/AutoTask/v1/indexDefinitions/default.json +++ b/plugins/AutoTask/v1/indexDefinitions/default.json @@ -83,6 +83,28 @@ "endDate" ] } + }, + { + "name": "TicketStatuses", + "dataStream": { "name": "ticketStatuses" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "autotask-ticket-status" }, + "properties": [] + } + }, + { + "name": "TicketPriorities", + "dataStream": { "name": "ticketPriorities" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "autotask-ticket-priority" }, + "properties": [] + } } ] } diff --git a/plugins/AutoTask/v1/metadata.json b/plugins/AutoTask/v1/metadata.json index 03e059c..59f440a 100644 --- a/plugins/AutoTask/v1/metadata.json +++ b/plugins/AutoTask/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "autotask", "displayName": "Autotask", - "version": "1.0.1", + "version": "1.0.4", "author": { "name": "@TimWheeler-SQUP", "type": "community"