diff --git a/plugins/PagerDuty/v2/configValidation.json b/plugins/PagerDuty/v2/configValidation.json new file mode 100644 index 00000000..04f305cb --- /dev/null +++ b/plugins/PagerDuty/v2/configValidation.json @@ -0,0 +1,11 @@ +{ + "steps": [ + { + "displayName": "Authenticate", + "dataStream": { "name": "validateAuth" }, + "required": true, + "error": "Could not authenticate with PagerDuty. Check that your API token and service region are correct.", + "success": "Connected to PagerDuty successfully." + } + ] +} diff --git a/plugins/PagerDuty/v2/custom_types.json b/plugins/PagerDuty/v2/custom_types.json new file mode 100644 index 00000000..5609c431 --- /dev/null +++ b/plugins/PagerDuty/v2/custom_types.json @@ -0,0 +1,37 @@ +[ + { + "name": "PagerDuty Service", + "sourceType": "PagerDuty Service", + "icon": "bell", + "singular": "Service", + "plural": "Services" + }, + { + "name": "PagerDuty User", + "sourceType": "PagerDuty User", + "icon": "user", + "singular": "User", + "plural": "Users" + }, + { + "name": "PagerDuty Team", + "sourceType": "PagerDuty Team", + "icon": "people-group", + "singular": "Team", + "plural": "Teams" + }, + { + "name": "PagerDuty Schedule", + "sourceType": "PagerDuty Schedule", + "icon": "calendar-days", + "singular": "Schedule", + "plural": "Schedules" + }, + { + "name": "PagerDuty Escalation Policy", + "sourceType": "PagerDuty Escalation Policy", + "icon": "diagram-project", + "singular": "Escalation Policy", + "plural": "Escalation Policies" + } +] diff --git a/plugins/PagerDuty/v2/dataStreams/escalationPolicies.json b/plugins/PagerDuty/v2/dataStreams/escalationPolicies.json new file mode 100644 index 00000000..cf42dc33 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/escalationPolicies.json @@ -0,0 +1,31 @@ +{ + "name": "escalationPolicies", + "displayName": "Escalation Policies (Import)", + "description": "One row per PagerDuty escalation policy with its team associations", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "escalation_policies", + "postRequestScript": "escalationPolicies.js", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "escalation_policies" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + } + }, + "matches": "none", + "metadata": [ + { "name": "id", "shape": "string" }, + { "name": "name", "shape": "string" }, + { "name": "num_loops", "displayName": "Number of Loops", "shape": "number" }, + { "name": "teamIds", "displayName": "Team IDs", "shape": "string" }, + { "name": "teamNames", "displayName": "Team Names", "shape": "string" } + ], + "timeframes": false, + "visibility": { "type": "hidden" } +} diff --git a/plugins/PagerDuty/v2/dataStreams/incidentMetrics.json b/plugins/PagerDuty/v2/dataStreams/incidentMetrics.json new file mode 100644 index 00000000..14ae913c --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/incidentMetrics.json @@ -0,0 +1,97 @@ +{ + "name": "incidentMetrics", + "displayName": "Incident Metrics", + "description": "Account-wide aggregated incident analytics — MTTA, MTTR, escalation and interruption counts, optionally bucketed by day, week or month", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "endpointPath": "analytics/metrics/incidents/all", + "postBody": { + "filters": { + "created_at_start": "{{timeframe.start}}", + "created_at_end": "{{timeframe.end}}", + "urgency": "{{urgency && urgency !== 'none' ? urgency : null}}", + "team_ids": "{{team?.flatMap(o => o.rawId) || null}}", + "service_ids": "{{service?.flatMap(o => o.rawId) || null}}" + }, + "time_zone": "{{dataSource.timezone}}", + "aggregate_unit": "{{aggregateUnit && aggregateUnit !== 'none' ? aggregateUnit : null}}" + }, + "pathToData": "data" + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "switch", + "name": "aggregateUnit", + "label": "Bucket by", + "help": "Leave as None for a single account-wide summary row over the selected timeframe.", + "defaultValue": "none", + "options": [ + { "value": "none", "label": "None" }, + { "value": "day", "label": "Day" }, + { "value": "week", "label": "Week" }, + { "value": "month", "label": "Month" } + ] + }, + { + "type": "switch", + "name": "urgency", + "label": "Urgency", + "defaultValue": "none", + "options": [ + { "value": "none", "label": "None" }, + { "value": "high", "label": "High" }, + { "value": "low", "label": "Low" } + ] + }, + { + "type": "objects", + "name": "service", + "label": "Service", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Service"] } } + }, + { + "type": "objects", + "name": "team", + "label": "Team", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Team"] } } + } + ], + "metadata": [ + { "name": "range_start", "displayName": "Period", "shape": "date", "role": "timestamp" }, + { "name": "total_incident_count", "displayName": "Incidents", "shape": ["number", { "thousandsSeparator": true }], "role": "value" }, + { "name": "total_incidents_acknowledged", "displayName": "Acknowledged", "shape": "number" }, + { "name": "total_incidents_auto_resolved", "displayName": "Auto-Resolved", "shape": "number" }, + { + "name": "manuallyResolvedCount", + "displayName": "Incidents Minus Auto-Resolved", + "computed": true, + "valueExpression": "{{ ($['total_incident_count'] || 0) - ($['total_incidents_auto_resolved'] || 0) }}", + "shape": ["number", { "thousandsSeparator": true }] + }, + { "name": "total_incidents_manual_escalated", "displayName": "Manually Escalated", "shape": "number" }, + { "name": "total_incidents_timeout_escalated", "displayName": "Timeout-Escalated", "shape": "number" }, + { "name": "total_incidents_reassigned", "displayName": "Reassigned", "shape": "number" }, + { "name": "total_escalation_count", "displayName": "Escalations", "shape": "number" }, + { "name": "total_interruptions", "displayName": "Interruptions", "shape": "number" }, + { "name": "total_business_hour_interruptions", "displayName": "Business-Hour Interruptions", "shape": "number", "visible": false }, + { "name": "total_off_hour_interruptions", "displayName": "Off-Hour Interruptions", "shape": "number", "visible": false }, + { "name": "total_sleep_hour_interruptions", "displayName": "Sleep-Hour Interruptions", "shape": "number", "visible": false }, + { "name": "total_notifications", "displayName": "Notifications", "shape": "number", "visible": false }, + { "name": "mean_seconds_to_first_ack", "displayName": "Mean Time to Acknowledge", "shape": "seconds" }, + { "name": "mean_seconds_to_resolve", "displayName": "Mean Time to Resolve", "shape": "seconds" }, + { "name": "mean_seconds_to_engage", "displayName": "Mean Time to Engage", "shape": "seconds", "visible": false }, + { "name": "mean_seconds_to_mobilize", "displayName": "Mean Time to Mobilize", "shape": "seconds", "visible": false }, + { "name": "mean_engaged_seconds", "displayName": "Mean Engaged Time", "shape": "seconds", "visible": false }, + { "name": "total_engaged_seconds", "displayName": "Total Engaged Time", "shape": "seconds", "visible": false }, + { "name": "mean_assignment_count", "displayName": "Mean Assignments", "shape": "number", "visible": false }, + { "name": "mean_engaged_user_count", "displayName": "Mean Engaged Users", "shape": "number", "visible": false }, + { "name": "up_time_pct", "displayName": "Uptime", "shape": "percent" } + ], + "timeframes": true, + "defaultTimeframe": "dashboard" +} diff --git a/plugins/PagerDuty/v2/dataStreams/incidentMetricsBreakdown.json b/plugins/PagerDuty/v2/dataStreams/incidentMetricsBreakdown.json new file mode 100644 index 00000000..2dd861ce --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/incidentMetricsBreakdown.json @@ -0,0 +1,82 @@ +{ + "name": "incidentMetricsBreakdown", + "displayName": "Incident Metrics (by Service / Team / Escalation Policy)", + "description": "Aggregated incident analytics grouped by service, team or escalation policy, one row per group", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "endpointPath": "analytics/metrics/incidents/{{groupBy}}", + "postBody": { + "filters": { + "created_at_start": "{{timeframe.start}}", + "created_at_end": "{{timeframe.end}}", + "urgency": "{{urgency && urgency !== 'none' ? urgency : null}}", + "team_ids": "{{team?.flatMap(o => o.rawId) || null}}", + "service_ids": "{{service?.flatMap(o => o.rawId) || null}}" + }, + "time_zone": "{{dataSource.timezone}}" + }, + "pathToData": "data" + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "switch", + "name": "groupBy", + "label": "Group by", + "defaultValue": "services", + "options": [ + { "value": "services", "label": "Service" }, + { "value": "teams", "label": "Team" }, + { "value": "escalation_policies", "label": "Escalation Policy" } + ], + "validation": { "required": true } + }, + { + "type": "switch", + "name": "urgency", + "label": "Urgency", + "defaultValue": "none", + "options": [ + { "value": "none", "label": "None" }, + { "value": "high", "label": "High" }, + { "value": "low", "label": "Low" } + ] + }, + { + "type": "objects", + "name": "service", + "label": "Service", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Service"] } } + }, + { + "type": "objects", + "name": "team", + "label": "Team", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Team"] } } + } + ], + "metadata": [ + { "name": "service_id", "displayName": "Service ID", "shape": "string", "visible": false }, + { "name": "service_name", "displayName": "Service", "shape": "string", "role": "label" }, + { "name": "team_id", "displayName": "Team ID", "shape": "string", "visible": false }, + { "name": "team_name", "displayName": "Team", "shape": "string" }, + { "name": "escalation_policy_id", "displayName": "Escalation Policy ID", "shape": "string", "visible": false }, + { "name": "escalation_policy_name", "displayName": "Escalation Policy", "shape": "string" }, + { "name": "distinct_responder_count", "displayName": "Distinct Responders", "shape": "number" }, + { "name": "total_incident_count", "displayName": "Incidents", "shape": ["number", { "thousandsSeparator": true }], "role": "value" }, + { "name": "total_incidents_acknowledged", "displayName": "Acknowledged", "shape": "number" }, + { "name": "total_incidents_auto_resolved", "displayName": "Auto-Resolved", "shape": "number" }, + { "name": "total_escalation_count", "displayName": "Escalations", "shape": "number" }, + { "name": "total_interruptions", "displayName": "Interruptions", "shape": "number" }, + { "name": "mean_seconds_to_first_ack", "displayName": "Mean Time to Acknowledge", "shape": "seconds" }, + { "name": "mean_seconds_to_resolve", "displayName": "Mean Time to Resolve", "shape": "seconds" }, + { "name": "up_time_pct", "displayName": "Uptime", "shape": "percent" }, + { "sourceId": "service_id", "sourceType": "PagerDuty Service", "name": "service_name" } + ], + "timeframes": true, + "defaultTimeframe": "dashboard" +} diff --git a/plugins/PagerDuty/v2/dataStreams/incidents.json b/plugins/PagerDuty/v2/dataStreams/incidents.json new file mode 100644 index 00000000..43052c41 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/incidents.json @@ -0,0 +1,124 @@ +{ + "name": "incidents", + "displayName": "Incidents", + "description": "PagerDuty incidents filterable by status, urgency, service, team and assignee, one row per incident. PagerDuty's incident search only supports a ~6-month lookback, so a longer or custom range is automatically clamped to the most recent 6 months.", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "incidents", + "getArgs": [ + { "key": "since", "value": "{{new Date(Math.max(new Date(timeframe.start).getTime(), new Date(timeframe.end).getTime() - 182 * 86400000)).toISOString()}}" }, + { "key": "until", "value": "{{timeframe.end}}" }, + { "key": "statuses[]", "value": "{{statuses?.length ? statuses : null}}" }, + { "key": "urgencies[]", "value": "{{urgencies?.length ? urgencies : null}}" }, + { "key": "service_ids[]", "value": "{{service?.flatMap(o => o.rawId) || null}}" }, + { "key": "team_ids[]", "value": "{{team?.flatMap(o => o.rawId) || null}}" }, + { "key": "user_ids[]", "value": "{{assignee?.flatMap(o => o.rawId) || null}}" } + ], + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "incidents" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + }, + "postRequestScript": "incidents.js" + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "autocomplete", + "name": "statuses", + "label": "Status", + "isMulti": true, + "allowCustomValues": false, + "placeholder": "Select...", + "help": "Leave empty to include all statuses. Filtering here is done by PagerDuty rather than in the browser, keeping large result sets manageable.", + "data": { + "source": "fixed", + "values": [ + { "value": "triggered", "label": "Triggered" }, + { "value": "acknowledged", "label": "Acknowledged" }, + { "value": "resolved", "label": "Resolved" } + ] + } + }, + { + "type": "autocomplete", + "name": "urgencies", + "label": "Urgency", + "isMulti": true, + "allowCustomValues": false, + "placeholder": "Select...", + "help": "Leave empty to include all urgencies.", + "data": { + "source": "fixed", + "values": [ + { "value": "high", "label": "High" }, + { "value": "low", "label": "Low" } + ] + } + }, + { + "type": "objects", + "name": "service", + "label": "Service", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Service"] } } + }, + { + "type": "objects", + "name": "team", + "label": "Team", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Team"] } } + }, + { + "type": "objects", + "name": "assignee", + "label": "Assignee", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty User"] } } + } + ], + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "visible": false }, + { "name": "incidentNumber", "displayName": "Number", "shape": ["number", { "thousandsSeparator": false }] }, + { "name": "title", "displayName": "Title", "shape": "string", "role": "label" }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "error": ["triggered"], + "warning": ["acknowledged"], + "success": ["resolved"] + } + } + ] + }, + { "name": "urgency", "displayName": "Urgency", "shape": "string" }, + { "name": "priorityName", "displayName": "Priority", "shape": "string" }, + { "name": "serviceId", "displayName": "Service ID", "shape": "string", "visible": false }, + { "name": "serviceName", "displayName": "Service", "shape": "string" }, + { "name": "escalationPolicyName", "displayName": "Escalation Policy", "shape": "string", "visible": false }, + { "name": "teamNames", "displayName": "Teams", "shape": "string" }, + { "name": "assigneeNames", "displayName": "Assignees", "shape": "string" }, + { "name": "modifiedById", "displayName": "Modified By ID", "shape": "string", "visible": false }, + { "name": "modifiedByName", "displayName": "Modified By", "shape": "string" }, + { "name": "modifiedByType", "displayName": "Modified By Type", "shape": "string", "visible": false }, + { "name": "createdAt", "displayName": "Created", "shape": "date", "role": "timestamp" }, + { "name": "lastStatusChangeAt", "displayName": "Last Status Change", "shape": "date" }, + { "name": "resolvedAt", "displayName": "Resolved", "shape": "date" }, + { "name": "htmlUrl", "displayName": "Link", "shape": ["url", { "label": "Open in PagerDuty" }] }, + { "sourceId": "serviceId", "sourceType": "PagerDuty Service", "name": "serviceName" } + ], + "timeframes": true, + "defaultTimeframe": "dashboard" +} diff --git a/plugins/PagerDuty/v2/dataStreams/notifications.json b/plugins/PagerDuty/v2/dataStreams/notifications.json new file mode 100644 index 00000000..9f9aabec --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/notifications.json @@ -0,0 +1,61 @@ +{ + "name": "notifications", + "displayName": "Notifications", + "description": "Outbound notifications sent to responders, one row per notification", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "notifications", + "getArgs": [ + { "key": "since", "value": "{{timeframe.start}}" }, + { "key": "until", "value": "{{timeframe.end}}" }, + { "key": "filter", "value": "{{channel && channel !== 'none' ? channel : null}}" } + ], + "postRequestScript": "notifications.js", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "notifications" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + } + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "objects", + "name": "user", + "label": "User", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty User"] } } + }, + { + "type": "switch", + "name": "channel", + "label": "Channel", + "defaultValue": "none", + "options": [ + { "value": "none", "label": "None" }, + { "value": "sms_notification", "label": "SMS" }, + { "value": "email_notification", "label": "Email" }, + { "value": "phone_notification", "label": "Phone" }, + { "value": "push_notification", "label": "Push" } + ] + } + ], + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "visible": false }, + { "name": "type", "displayName": "Channel", "shape": "string" }, + { "name": "address", "displayName": "Address", "shape": "string" }, + { "name": "user.id", "displayName": "User ID", "shape": "string", "visible": false }, + { "name": "user.summary", "displayName": "User", "shape": "string", "role": "label" }, + { "name": "started_at", "displayName": "Sent", "shape": "date", "role": "timestamp" }, + { "sourceId": "user.id", "sourceType": "PagerDuty User", "name": "user.summary" } + ], + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"], + "defaultTimeframe": "dashboard" +} diff --git a/plugins/PagerDuty/v2/dataStreams/onCall.json b/plugins/PagerDuty/v2/dataStreams/onCall.json new file mode 100644 index 00000000..9f79ce62 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/onCall.json @@ -0,0 +1,75 @@ +{ + "name": "onCall", + "displayName": "On-Call", + "description": "Who is on call now and over an upcoming look-ahead window, one row per on-call shift", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "oncalls", + "pathToData": "oncalls", + "expandInnerObjects": true, + "getArgs": [ + { "key": "since", "value": "{{new Date().toISOString()}}" }, + { "key": "until", "value": "{{new Date(Date.now() + Number(lookAheadDays || 1) * 86400000).toISOString()}}" }, + { "key": "user_ids[]", "value": "{{user?.flatMap(o => o.rawId) || null}}" }, + { "key": "schedule_ids[]", "value": "{{schedule?.flatMap(o => o.rawId) || null}}" }, + { "key": "escalation_policy_ids[]", "value": "{{escalationPolicy?.flatMap(o => o.rawId) || null}}" } + ], + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "oncalls" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + } + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "number", + "name": "lookAheadDays", + "label": "Look-ahead window (days)", + "help": "How far into the future to check the on-call schedule. Defaults to 1 (who's on call right now).", + "placeholder": "Enter...", + "defaultValue": 1 + }, + { + "type": "objects", + "name": "user", + "label": "User", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty User"] } } + }, + { + "type": "objects", + "name": "schedule", + "label": "Schedule", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Schedule"] } } + }, + { + "type": "objects", + "name": "escalationPolicy", + "label": "Escalation Policy", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Escalation Policy"] } } + } + ], + "metadata": [ + { "name": "user.id", "displayName": "User ID", "shape": "string", "visible": false }, + { "name": "user.summary", "displayName": "User", "shape": "string", "role": "label" }, + { "name": "schedule.id", "displayName": "Schedule ID", "shape": "string", "visible": false }, + { "name": "schedule.summary", "displayName": "Schedule", "shape": "string" }, + { "name": "escalation_policy.id", "displayName": "Escalation Policy ID", "shape": "string", "visible": false }, + { "name": "escalation_policy.summary", "displayName": "Escalation Policy", "shape": "string" }, + { "name": "escalation_level", "displayName": "Escalation Level", "shape": "number" }, + { "name": "start", "displayName": "Start", "shape": "date", "role": "timestamp" }, + { "name": "end", "displayName": "End", "shape": "date" }, + { "sourceId": "user.id", "sourceType": "PagerDuty User", "name": "user.summary" } + ], + "timeframes": false +} diff --git a/plugins/PagerDuty/v2/dataStreams/responderMetrics.json b/plugins/PagerDuty/v2/dataStreams/responderMetrics.json new file mode 100644 index 00000000..e535c326 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/responderMetrics.json @@ -0,0 +1,67 @@ +{ + "name": "responderMetrics", + "displayName": "Responder Metrics", + "description": "Aggregated responder performance — incident load, mean time to acknowledge and on-call time, one row per responder", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "endpointPath": "analytics/metrics/responders", + "postBody": { + "filters": { + "date_range_start": "{{timeframe.start}}", + "date_range_end": "{{timeframe.end}}", + "urgency": "{{urgency && urgency !== 'none' ? urgency : null}}", + "team_ids": "{{team?.flatMap(o => o.rawId) || null}}", + "responder_ids": "{{user?.flatMap(o => o.rawId) || null}}" + }, + "time_zone": "{{dataSource.timezone}}" + }, + "pathToData": "data" + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "switch", + "name": "urgency", + "label": "Urgency", + "defaultValue": "none", + "options": [ + { "value": "none", "label": "None" }, + { "value": "high", "label": "High" }, + { "value": "low", "label": "Low" } + ] + }, + { + "type": "objects", + "name": "team", + "label": "Team", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Team"] } } + }, + { + "type": "objects", + "name": "user", + "label": "Responder", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty User"] } } + } + ], + "metadata": [ + { "name": "responder_id", "displayName": "Responder ID", "shape": "string", "visible": false }, + { "name": "responder_name", "displayName": "Responder", "shape": "string", "role": "label" }, + { "name": "total_incident_count", "displayName": "Incidents", "shape": ["number", { "thousandsSeparator": true }], "role": "value" }, + { "name": "total_incidents_acknowledged", "displayName": "Acknowledged", "shape": "number" }, + { "name": "total_interruptions", "displayName": "Interruptions", "shape": "number" }, + { "name": "total_notifications", "displayName": "Notifications", "shape": "number", "visible": false }, + { "name": "mean_time_to_acknowledge_seconds", "displayName": "Mean Time to Acknowledge", "shape": "seconds" }, + { "name": "mean_engaged_seconds", "displayName": "Mean Engaged Time", "shape": "seconds", "visible": false }, + { "name": "total_engaged_seconds", "displayName": "Total Engaged Time", "shape": "seconds", "visible": false }, + { "name": "total_seconds_on_call", "displayName": "Time On-Call", "shape": "seconds" }, + { "name": "total_seconds_on_call_level_1", "displayName": "Time On-Call (Level 1)", "shape": "seconds", "visible": false }, + { "name": "total_seconds_on_call_level_2_plus", "displayName": "Time On-Call (Level 2+)", "shape": "seconds", "visible": false }, + { "sourceId": "responder_id", "sourceType": "PagerDuty User", "name": "responder_name" } + ], + "timeframes": true, + "defaultTimeframe": "dashboard" +} diff --git a/plugins/PagerDuty/v2/dataStreams/schedules.json b/plugins/PagerDuty/v2/dataStreams/schedules.json new file mode 100644 index 00000000..7a7f8d3b --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/schedules.json @@ -0,0 +1,30 @@ +{ + "name": "schedules", + "displayName": "Schedules (Import)", + "description": "One row per PagerDuty on-call schedule", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "schedules", + "pathToData": "schedules", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "schedules" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + } + }, + "matches": "none", + "metadata": [ + { "name": "id", "shape": "string" }, + { "name": "name", "shape": "string" }, + { "name": "time_zone", "displayName": "Timezone", "shape": "string" }, + { "name": "description", "displayName": "Description", "shape": "string" } + ], + "timeframes": false, + "visibility": { "type": "hidden" } +} diff --git a/plugins/PagerDuty/v2/dataStreams/scripts/escalationPolicies.js b/plugins/PagerDuty/v2/dataStreams/scripts/escalationPolicies.js new file mode 100644 index 00000000..97761ba3 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/scripts/escalationPolicies.js @@ -0,0 +1,9 @@ +const rows = data.escalation_policies || []; + +result = rows.map((p) => ({ + id: p.id, + name: p.name, + num_loops: p.num_loops, + teamIds: (p.teams || []).map((t) => t.id).join(","), + teamNames: (p.teams || []).map((t) => t.summary).join(", "), +})); diff --git a/plugins/PagerDuty/v2/dataStreams/scripts/incidents.js b/plugins/PagerDuty/v2/dataStreams/scripts/incidents.js new file mode 100644 index 00000000..adc73a26 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/scripts/incidents.js @@ -0,0 +1,25 @@ +const rows = data.incidents || []; + +result = rows.map((i) => ({ + id: i.id, + incidentNumber: i.incident_number, + title: i.title, + status: i.status, + urgency: i.urgency, + priorityName: i.priority ? i.priority.summary : "", + serviceId: i.service ? i.service.id : "", + serviceName: i.service ? i.service.summary : "", + escalationPolicyName: i.escalation_policy ? i.escalation_policy.summary : "", + teamNames: (i.teams || []).map((t) => t.summary).join(", "), + assigneeNames: (i.assignments || []) + .map((a) => a.assignee && a.assignee.summary) + .filter(Boolean) + .join(", "), + modifiedById: i.last_status_change_by ? i.last_status_change_by.id : "", + modifiedByName: i.last_status_change_by ? i.last_status_change_by.summary : "", + modifiedByType: i.last_status_change_by ? i.last_status_change_by.type : "", + createdAt: i.created_at, + lastStatusChangeAt: i.last_status_change_at, + resolvedAt: i.resolved_at || "", + htmlUrl: i.html_url, +})); diff --git a/plugins/PagerDuty/v2/dataStreams/scripts/notifications.js b/plugins/PagerDuty/v2/dataStreams/scripts/notifications.js new file mode 100644 index 00000000..b70dc33d --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/scripts/notifications.js @@ -0,0 +1,20 @@ +// Optional `user` object-picker parameter (stream `ui` name "user"). +// PagerDuty's GET /notifications endpoint has no server-side user filter, +// so scoping is done client-side here. Selected objects arrive at +// context.config.user as an ARRAY (multi-select), each rawId a single-element +// array. Empty/absent -> account-wide, no filter. +const unwrap = (v) => (Array.isArray(v) ? v[0] : v); +const selected = (context.config && context.config.user) || []; +const selectedIds = new Set(selected.map((o) => unwrap(o.rawId)).filter(Boolean)); + +const rows = data.notifications || []; +const scoped = selectedIds.size ? rows.filter((n) => n.user && selectedIds.has(n.user.id)) : rows; + +result = scoped.map((n) => ({ + id: n.id, + type: n.type, + address: n.address || "", + "user.id": n.user ? n.user.id : "", + "user.summary": n.user ? n.user.summary : "", + started_at: n.started_at, +})); diff --git a/plugins/PagerDuty/v2/dataStreams/scripts/services.js b/plugins/PagerDuty/v2/dataStreams/scripts/services.js new file mode 100644 index 00000000..b187cb95 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/scripts/services.js @@ -0,0 +1,22 @@ +// Optional `service` object-picker parameter (stream `ui` name "service"). +// Selected objects arrive at context.config.service as an ARRAY (multi-select), +// each rawId a single-element array. Empty/absent -> account-wide, no filter. +const unwrap = (v) => (Array.isArray(v) ? v[0] : v); +const selected = (context.config && context.config.service) || []; +const selectedIds = new Set(selected.map((o) => unwrap(o.rawId)).filter(Boolean)); + +const rows = data.services || []; +const scoped = selectedIds.size ? rows.filter((s) => selectedIds.has(s.id)) : rows; + +result = scoped.map((s) => ({ + id: s.id, + name: s.name, + status: s.status, + description: s.description || "", + escalationPolicyId: s.escalation_policy ? s.escalation_policy.id : "", + escalationPolicyName: s.escalation_policy ? s.escalation_policy.summary : "", + teamIds: (s.teams || []).map((t) => t.id).join(","), + teamNames: (s.teams || []).map((t) => t.summary).join(", "), + alertCreation: s.alert_creation || "", + htmlUrl: s.html_url, +})); diff --git a/plugins/PagerDuty/v2/dataStreams/scripts/users.js b/plugins/PagerDuty/v2/dataStreams/scripts/users.js new file mode 100644 index 00000000..d22ec8df --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/scripts/users.js @@ -0,0 +1,21 @@ +// Optional `user` object-picker parameter (stream `ui` name "user"). +// Selected objects arrive at context.config.user as an ARRAY (multi-select), +// each rawId a single-element array. Empty/absent -> account-wide, no filter. +const unwrap = (v) => (Array.isArray(v) ? v[0] : v); +const selected = (context.config && context.config.user) || []; +const selectedIds = new Set(selected.map((o) => unwrap(o.rawId)).filter(Boolean)); + +const rows = data.users || []; +const scoped = selectedIds.size ? rows.filter((u) => selectedIds.has(u.id)) : rows; + +result = scoped.map((u) => ({ + id: u.id, + name: u.name, + email: u.email, + role: u.role, + jobTitle: u.job_title || "", + timezone: u.time_zone || "", + teamIds: (u.teams || []).map((t) => t.id).join(","), + teamNames: (u.teams || []).map((t) => t.summary).join(", "), + htmlUrl: u.html_url, +})); diff --git a/plugins/PagerDuty/v2/dataStreams/services.json b/plugins/PagerDuty/v2/dataStreams/services.json new file mode 100644 index 00000000..47d629aa --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/services.json @@ -0,0 +1,60 @@ +{ + "name": "services", + "displayName": "Services", + "description": "PagerDuty services with current status, escalation policy and team associations, one row per service", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "services", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "services" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + }, + "postRequestScript": "services.js" + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "objects", + "name": "service", + "label": "Service", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Service"] } } + } + ], + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, + { "name": "name", "displayName": "Name", "shape": "string", "role": "label" }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "success": ["active"], + "warning": ["warning", "maintenance"], + "error": ["critical"], + "unmonitored": ["disabled"] + } + } + ] + }, + { "name": "description", "displayName": "Description", "shape": "string" }, + { "name": "escalationPolicyId", "displayName": "Escalation Policy ID", "shape": "string", "visible": false }, + { "name": "escalationPolicyName", "displayName": "Escalation Policy", "shape": "string" }, + { "name": "teamIds", "displayName": "Team IDs", "shape": "string", "visible": false }, + { "name": "teamNames", "displayName": "Teams", "shape": "string" }, + { "name": "alertCreation", "displayName": "Alert Creation", "shape": "string", "visible": false }, + { "name": "htmlUrl", "displayName": "Link", "shape": ["url", { "label": "Open in PagerDuty" }] }, + { "sourceId": "id", "sourceType": "PagerDuty Service", "name": "name" } + ], + "timeframes": false +} diff --git a/plugins/PagerDuty/v2/dataStreams/teams.json b/plugins/PagerDuty/v2/dataStreams/teams.json new file mode 100644 index 00000000..af4c4d2f --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/teams.json @@ -0,0 +1,29 @@ +{ + "name": "teams", + "displayName": "Teams (Import)", + "description": "One row per PagerDuty team", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "teams", + "pathToData": "teams", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "teams" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + } + }, + "matches": "none", + "metadata": [ + { "name": "id", "shape": "string" }, + { "name": "name", "shape": "string" }, + { "name": "description", "displayName": "Description", "shape": "string" } + ], + "timeframes": false, + "visibility": { "type": "hidden" } +} diff --git a/plugins/PagerDuty/v2/dataStreams/users.json b/plugins/PagerDuty/v2/dataStreams/users.json new file mode 100644 index 00000000..0c6cae9a --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/users.json @@ -0,0 +1,45 @@ +{ + "name": "users", + "displayName": "Users", + "description": "PagerDuty user roster with role, contact and team associations, one row per user", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "users", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "limit", "value": "100" }, + "offset": { + "mode": "row", + "rowCountIn": { "realm": "payloadArraySize", "path": "users" }, + "base": 0 + }, + "out": { "realm": "queryArg", "path": "offset" } + }, + "postRequestScript": "users.js" + }, + "matches": "none", + "manualConfigApply": true, + "ui": [ + { + "type": "objects", + "name": "user", + "label": "User", + "placeholder": "Select...", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty User"] } } + } + ], + "metadata": [ + { "name": "id", "displayName": "ID", "shape": "string", "role": "id", "visible": false }, + { "name": "name", "displayName": "Name", "shape": "string", "role": "label" }, + { "name": "email", "displayName": "Email", "shape": "string" }, + { "name": "role", "displayName": "Role", "shape": "string" }, + { "name": "jobTitle", "displayName": "Job Title", "shape": "string" }, + { "name": "timezone", "displayName": "Timezone", "shape": "string", "visible": false }, + { "name": "teamIds", "displayName": "Team IDs", "shape": "string", "visible": false }, + { "name": "teamNames", "displayName": "Teams", "shape": "string" }, + { "name": "htmlUrl", "displayName": "Link", "shape": ["url", { "label": "Open in PagerDuty" }] }, + { "sourceId": "id", "sourceType": "PagerDuty User", "name": "name" } + ], + "timeframes": false +} diff --git a/plugins/PagerDuty/v2/dataStreams/validateAuth.json b/plugins/PagerDuty/v2/dataStreams/validateAuth.json new file mode 100644 index 00000000..77ce3261 --- /dev/null +++ b/plugins/PagerDuty/v2/dataStreams/validateAuth.json @@ -0,0 +1,16 @@ +{ + "name": "validateAuth", + "displayName": "Authentication Validation", + "description": "Returns the calling account's enabled ability flags", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "abilities" + }, + "matches": "none", + "metadata": [{ "pattern": ".*" }], + "timeframes": false, + "visibility": { + "type": "hidden" + } +} diff --git a/plugins/PagerDuty/v2/defaultContent/manifest.json b/plugins/PagerDuty/v2/defaultContent/manifest.json new file mode 100644 index 00000000..a321cd51 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/manifest.json @@ -0,0 +1,9 @@ +{ + "items": [ + { "name": "overview", "type": "dashboard" }, + { "name": "onCall", "type": "dashboard" }, + { "name": "servicePerspective", "type": "dashboard" }, + { "name": "userPerspective", "type": "dashboard" }, + { "name": "teamPerspective", "type": "dashboard" } + ] +} diff --git a/plugins/PagerDuty/v2/defaultContent/onCall.dash.json b/plugins/PagerDuty/v2/defaultContent/onCall.dash.json new file mode 100644 index 00000000..d7c4aea4 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/onCall.dash.json @@ -0,0 +1,122 @@ +{ + "name": "On-Call", + "schemaVersion": "1.5", + "timeframe": "last30days", + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "af2ee963-8f1f-400c-8096-15b90e619e60", + "x": 0, + "y": 0, + "w": 2, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "On Call Now", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[onCall]}}", + "name": "onCall", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["user.summary", "schedule.summary", "escalation_policy.summary", "escalation_level"], + "hiddenColumns": ["start", "end"] + } + } + } + } + }, + { + "i": "aadc00db-6dee-4646-a705-c80a2c7edae1", + "x": 2, + "y": 0, + "w": 2, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "On Call — Next 7 Days", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[onCall]}}", + "name": "onCall", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { "lookAheadDays": 7 } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["user.summary", "schedule.summary", "escalation_policy.summary", "start", "end"], + "hiddenColumns": ["escalation_level"] + } + } + } + } + }, + { + "i": "2546b468-e0f3-42cd-a3dd-a5c9a3eb13da", + "x": 0, + "y": 4, + "w": 4, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "On-Call Time by Responder", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[responderMetrics]}}", + "name": "responderMetrics", + "pluginConfigId": "{{configId}}", + "sort": { "by": [["total_seconds_on_call", "desc"]], "top": 10 } + }, + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "responder_name", + "yAxisData": ["total_seconds_on_call"], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "Time on-call", + "showXAxisLabel": false, + "showYAxisLabel": true, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { "type": "auto" } + } + } + } + } + } + ] + } +} diff --git a/plugins/PagerDuty/v2/defaultContent/overview.dash.json b/plugins/PagerDuty/v2/defaultContent/overview.dash.json new file mode 100644 index 00000000..95def6c4 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/overview.dash.json @@ -0,0 +1,324 @@ +{ + "name": "Overview", + "schemaVersion": "1.5", + "timeframe": "last7days", + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "407b220f-5f82-44a3-bdac-0f914de10443", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Total Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_incident_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "bac1e487-341b-4bc3-b393-1021c8379e31", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Acknowledge", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_seconds_to_first_ack", "comparisonColumn": "none" } } + } + } + }, + { + "i": "c75fe14e-0736-44eb-ab6a-c5b0002d0ff4", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Resolve", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_seconds_to_resolve", "comparisonColumn": "none" } } + } + } + }, + { + "i": "24f1ba74-7985-4f5a-8fd9-3b61be83f034", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Escalations", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_escalation_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "e2976967-d5d0-4893-bc17-8854f82d938d", + "x": 0, + "y": 2, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents minus auto-resolved", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "manuallyResolvedCount", "comparisonColumn": "none" } } + } + } + }, + { + "i": "9bd9299c-e2fc-4b21-8d17-34b63438ef43", + "x": 0, + "y": 4, + "w": 2, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incident Volume", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { "aggregateUnit": "day" } + }, + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "range_start", + "yAxisColumn": ["total_incident_count"], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "yAxisLabel": "Incidents", + "showYAxisLabel": true, + "showTrendLine": false + } + } + } + } + }, + { + "i": "29f32962-a552-4874-b889-8634ee14596d", + "x": 2, + "y": 4, + "w": 2, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents by Status", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidents]}}", + "name": "incidents", + "pluginConfigId": "{{configId}}", + "group": { + "by": [["status", "uniqueValues"]], + "aggregate": [{ "type": "count" }] + } + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "status_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "ef478f65-dc08-47b7-b225-a726272fbe46", + "x": 0, + "y": 7, + "w": 2, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Top Services by Incident Volume", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetricsBreakdown]}}", + "name": "incidentMetricsBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { "groupBy": "services" }, + "sort": { "by": [["total_incident_count", "desc"]], "top": 10 } + }, + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "service_name", + "yAxisData": ["total_incident_count"], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "Incidents", + "showXAxisLabel": false, + "showYAxisLabel": true, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { "type": "auto" } + } + } + } + } + }, + { + "i": "f50ef53c-c8d9-4c24-9cb2-f38fca101cc0", + "x": 2, + "y": 7, + "w": 2, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "On-Call Now", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[onCall]}}", + "name": "onCall", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["user.summary", "schedule.summary", "escalation_policy.summary", "escalation_level", "start", "end"], + "hiddenColumns": [] + } + } + } + } + }, + { + "i": "06921b74-c2e9-4b5e-a46f-386f9ac88157", + "x": 0, + "y": 10, + "w": 4, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "Services Health", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[services]}}", + "name": "services", + "pluginConfigId": "{{configId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "status", + "sublabel": "escalationPolicyName", + "linkColumn": "name", + "columns": 6 + } + } + } + } + } + ] + } +} diff --git a/plugins/PagerDuty/v2/defaultContent/scopes.json b/plugins/PagerDuty/v2/defaultContent/scopes.json new file mode 100644 index 00000000..6876ef69 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/scopes.json @@ -0,0 +1,32 @@ +[ + { + "name": "Services", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Service"] } }, + "variable": { + "name": "PagerDuty Service", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Users", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty User"] } }, + "variable": { + "name": "PagerDuty User", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Teams", + "matches": { "sourceType": { "type": "oneOf", "values": ["PagerDuty Team"] } }, + "variable": { + "name": "PagerDuty Team", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + } +] diff --git a/plugins/PagerDuty/v2/defaultContent/servicePerspective.dash.json b/plugins/PagerDuty/v2/defaultContent/servicePerspective.dash.json new file mode 100644 index 00000000..460d8e49 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/servicePerspective.dash.json @@ -0,0 +1,324 @@ +{ + "name": "Service", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": ["{{variables.[PagerDuty Service]}}"], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "6b73dc4b-6a51-4c23-9bcc-2be9850113e2", + "x": 0, + "y": 0, + "w": 1, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "Service Details", + "description": "", + "variables": ["{{variables.[PagerDuty Service]}}"], + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { "id": "datastream-properties", "name": "properties" }, + "scope": { + "scope": "{{scopes.[Services]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[PagerDuty Service]}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { "data-stream-table": { "transpose": true } } + } + } + }, + { + "i": "c5ca7d80-fa56-4835-b202-b98d52d134f7", + "x": 1, + "y": 0, + "w": 1, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "Service Status", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[services]}}", + "name": "services", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "status", + "sublabel": "escalationPolicyName", + "linkColumn": "none", + "columns": 1 + } + } + } + } + }, + { + "i": "13465997-ceda-4f98-bc18-971a37455345", + "x": 2, + "y": 0, + "w": 2, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidents]}}", + "name": "incidents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["title", "status", "urgency", "createdAt"], + "hiddenColumns": ["priorityName", "teamNames", "assigneeNames", "lastStatusChangeAt", "resolvedAt"] + } + } + } + } + }, + { + "i": "a75b22c9-9092-45e8-aa14-5214c165acb3", + "x": 0, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Total Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_incident_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "267abc04-5b24-4880-867e-63eae5e227ca", + "x": 1, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Acknowledge", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_seconds_to_first_ack", "comparisonColumn": "none" } } + } + } + }, + { + "i": "b7b5aa5b-6706-4a4c-94c0-f49bb44520ed", + "x": 2, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Resolve", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_seconds_to_resolve", "comparisonColumn": "none" } } + } + } + }, + { + "i": "f4d5f444-775b-43c4-8384-715d3a730cac", + "x": 3, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Escalations", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_escalation_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "f4599a51-5c19-439c-98eb-bb31eb7382f0", + "x": 0, + "y": 6, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents minus auto-resolved", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "manuallyResolvedCount", "comparisonColumn": "none" } } + } + } + }, + { + "i": "06bb25db-4bf6-4be8-9ff4-d5c57b43e321", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incident Volume", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "aggregateUnit": "day", + "service": { + "variable": "{{variables.[PagerDuty Service]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Services]}}" + } + } + }, + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "range_start", + "yAxisColumn": ["total_incident_count"], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "yAxisLabel": "Incidents", + "showYAxisLabel": true, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/PagerDuty/v2/defaultContent/teamPerspective.dash.json b/plugins/PagerDuty/v2/defaultContent/teamPerspective.dash.json new file mode 100644 index 00000000..0a7d1597 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/teamPerspective.dash.json @@ -0,0 +1,291 @@ +{ + "name": "Team", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": ["{{variables.[PagerDuty Team]}}"], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "8c24adbd-b3db-4c04-ba5a-f2a36c6feba2", + "x": 0, + "y": 0, + "w": 1, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "Team Details", + "description": "", + "variables": ["{{variables.[PagerDuty Team]}}"], + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { "id": "datastream-properties", "name": "properties" }, + "scope": { + "scope": "{{scopes.[Teams]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[PagerDuty Team]}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { "data-stream-table": { "transpose": true } } + } + } + }, + { + "i": "f0150467-0090-4ad1-b8f7-85b724a8fa93", + "x": 1, + "y": 0, + "w": 3, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidents]}}", + "name": "incidents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["title", "status", "urgency", "serviceName", "createdAt"], + "hiddenColumns": ["priorityName", "escalationPolicyName", "teamNames", "assigneeNames", "lastStatusChangeAt", "resolvedAt"] + } + } + } + } + }, + { + "i": "3275a382-513c-4f25-80de-fa0fb98b1efe", + "x": 0, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Total Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_incident_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "a2efba9d-a311-4926-bb4e-cab9bc0d88ba", + "x": 1, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Acknowledge", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_seconds_to_first_ack", "comparisonColumn": "none" } } + } + } + }, + { + "i": "95ba432d-c9c3-42f7-ade6-4d5cf8f3d166", + "x": 2, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Resolve", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_seconds_to_resolve", "comparisonColumn": "none" } } + } + } + }, + { + "i": "6dfd9b3f-e6b2-43cf-ab8d-10eae2a5f450", + "x": 3, + "y": 4, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Escalations", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_escalation_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "7e13b2c1-55b1-45a0-8488-4f32f8358bf7", + "x": 0, + "y": 6, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents minus auto-resolved", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidentMetrics]}}", + "name": "incidentMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "manuallyResolvedCount", "comparisonColumn": "none" } } + } + } + }, + { + "i": "39dca1d8-9e66-4a18-9791-088761bed050", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Incidents by Responder", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[responderMetrics]}}", + "name": "responderMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "team": { + "variable": "{{variables.[PagerDuty Team]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Teams]}}" + } + }, + "sort": { "by": [["total_incident_count", "desc"]], "top": 10 } + }, + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "responder_name", + "yAxisData": ["total_incident_count"], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "Incidents", + "showXAxisLabel": false, + "showYAxisLabel": true, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { "type": "auto" } + } + } + } + } + } + ] + } +} diff --git a/plugins/PagerDuty/v2/defaultContent/userPerspective.dash.json b/plugins/PagerDuty/v2/defaultContent/userPerspective.dash.json new file mode 100644 index 00000000..fcb25932 --- /dev/null +++ b/plugins/PagerDuty/v2/defaultContent/userPerspective.dash.json @@ -0,0 +1,285 @@ +{ + "name": "User", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": ["{{variables.[PagerDuty User]}}"], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "74f4cad0-e543-44d0-98e0-0a718ae1babb", + "x": 0, + "y": 0, + "w": 1, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "User Details", + "description": "", + "variables": ["{{variables.[PagerDuty User]}}"], + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { "id": "datastream-properties", "name": "properties" }, + "scope": { + "scope": "{{scopes.[Users]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[PagerDuty User]}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { "data-stream-table": { "transpose": true } } + } + } + }, + { + "i": "f3fcc9c8-f0ff-40fd-9c55-f76ef91ae609", + "x": 1, + "y": 0, + "w": 3, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "timeframe": "none", + "_type": "tile/data-stream", + "title": "On-Call Shifts (Next 7 Days)", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[onCall]}}", + "name": "onCall", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "lookAheadDays": 7, + "user": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["schedule.summary", "escalation_policy.summary", "escalation_level", "start", "end"], + "hiddenColumns": [] + } + } + } + } + }, + { + "i": "e981dcef-e4c3-4bd5-83c3-73a70f32cf8f", + "x": 0, + "y": 4, + "w": 4, + "h": 4, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Assigned Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[incidents]}}", + "name": "incidents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "assignee": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["title", "status", "urgency", "serviceName", "createdAt"], + "hiddenColumns": ["priorityName", "escalationPolicyName", "teamNames", "lastStatusChangeAt", "resolvedAt"] + } + } + } + } + }, + { + "i": "5e572584-78eb-4602-abc3-b358e038c12a", + "x": 0, + "y": 8, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Total Incidents", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[responderMetrics]}}", + "name": "responderMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "user": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_incident_count", "comparisonColumn": "none" } } + } + } + }, + { + "i": "3ffa7813-94e8-4270-bbde-9c291dde03a2", + "x": 1, + "y": 8, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Mean Time to Acknowledge", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[responderMetrics]}}", + "name": "responderMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "user": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "mean_time_to_acknowledge_seconds", "comparisonColumn": "none" } } + } + } + }, + { + "i": "931731df-d1ac-4d8e-b618-941dc439529b", + "x": 2, + "y": 8, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Interruptions", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[responderMetrics]}}", + "name": "responderMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "user": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_interruptions", "comparisonColumn": "none" } } + } + } + }, + { + "i": "e02f7cd5-1b60-4c94-82c7-9e49b576d3cc", + "x": 3, + "y": 8, + "w": 1, + "h": 2, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Time On-Call", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[responderMetrics]}}", + "name": "responderMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "user": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { "data-stream-scalar": { "value": "total_seconds_on_call", "comparisonColumn": "none" } } + } + } + }, + { + "i": "3ab3c3fe-8c9f-4556-b0d2-001aa837b4aa", + "x": 0, + "y": 10, + "w": 4, + "h": 3, + "z": 0, + "moved": false, + "static": false, + "config": { + "_type": "tile/data-stream", + "title": "Recent Notifications", + "description": "", + "activePluginConfigIds": ["{{configId}}"], + "dataStream": { + "id": "{{dataStreams.[notifications]}}", + "name": "notifications", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "user": { + "variable": "{{variables.[PagerDuty User]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Users]}}" + } + } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": ["type", "status", "address", "started_at"], + "hiddenColumns": [] + } + } + } + } + } + ] + } +} diff --git a/plugins/PagerDuty/v2/docs/README.md b/plugins/PagerDuty/v2/docs/README.md new file mode 100644 index 00000000..19583ae7 --- /dev/null +++ b/plugins/PagerDuty/v2/docs/README.md @@ -0,0 +1,73 @@ +Monitor [PagerDuty](https://www.pagerduty.com) incidents, services, on-call +schedules and responder performance in SquaredUp, via the +[PagerDuty REST API](https://developer.pagerduty.com/api-reference). + +## Setup + +You will need a PagerDuty **REST API key**. + +1. Sign in to your [PagerDuty account](https://app.pagerduty.com). +2. Create the key from your user profile settings for a token tied to your own + user, or from your account's API access settings for a general-access key + that keeps working if your account is ever removed (creating one of those + requires admin permissions). Choose **Read-only** unless you have a reason + to grant write access. +3. Copy the generated key and paste it into the **API token** field. +4. Choose the **Service region** that matches your account — check your account + settings in PagerDuty if you're unsure; most accounts are **Global/US**. + +## Configuration fields + +| Field | What it is | Where to find it | Required | +| ----- | ---------- | ----------------- | -------- | +| **API token** | Authenticates every request via the `Authorization: Token token=...` header. | Your PagerDuty user profile settings (personal token) or account API access settings (general access). | Yes | +| **Service region** | Selects the PagerDuty API host (`api.pagerduty.com` or `api.eu.pagerduty.com`) for your account. | Your PagerDuty account settings. | Yes | +| **Timezone** | IANA timezone used to align time-based filters and aggregated results. | — | No | + +On save, the plugin validates the token by fetching your account's enabled +abilities; an invalid, expired, or revoked token fails setup with an +authentication error. + +## What this plugin monitors + +- **Incidents** — filterable by status, urgency, service, team and assignee, plus account-wide and per-service/team/escalation-policy aggregated analytics (MTTA, MTTR, escalation and interruption counts). +- **Services** — current status, escalation policy and team associations. +- **On-call** — who's on call now and over an upcoming look-ahead window, per user, schedule or escalation policy. +- **Users and responder performance** — roster, incident load, mean time to acknowledge, interruptions and time spent on-call. +- **Notifications** — outbound notifications sent to responders (SMS, email, phone, push). + +The out-of-the-box dashboards include an account-wide **Overview**, a dedicated **On-Call** dashboard, and a perspective for each **Service**, **User** and **Team**. + +## Data streams + +- **Services** — current status, escalation policy and team associations, one row per service. +- **Users** — role, contact and team associations, one row per user. +- **Incidents** — filterable by status, urgency, service, team and assignee, one row per incident, including who last modified/resolved it. +- **Incident Metrics** — account-wide aggregated incident analytics, optionally bucketed by day, week or month. +- **Incident Metrics (by Service / Team / Escalation Policy)** — the same analytics grouped by dimension, one row per group. +- **Responder Metrics** — aggregated responder performance, one row per responder. +- **On-Call** — who is on call now and over an upcoming look-ahead window, one row per shift. +- **Notifications** — outbound notifications sent to responders, one row per notification. + +## What gets indexed + +| Object type | API source | Represents | +| ----------- | ---------- | ---------- | +| **Service** | `GET /services` | A monitored PagerDuty service. | +| **User** | `GET /users` | A PagerDuty user who can respond to incidents. | +| **Team** | `GET /teams` | A group of users and services. | +| **Schedule** | `GET /schedules` | An on-call rotation schedule. | +| **Escalation Policy** | `GET /escalation_policies` | A set of escalation rules used by one or more services. | + +Team membership is stored as a property on each Service and User (`teamIds`/`teamNames`), not as a graph relationship — there is no direct drilldown from a Team to its member services or users. + +## Known limitations + +- **Incident search is capped at a 6-month window** — this is a hard limit of PagerDuty's own incident search API, not a SquaredUp restriction: a request spanning more than ~6 months is rejected outright. The **Incidents** stream offers every timeframe, including This Year, Last Year and a custom range, but automatically clamps the start of any wider selection to 6 months before the end so the query never fails — you'll silently get the most recent 6 months of a longer range. Use **Incident Metrics** for longer-range trend analysis, which has no such cap. +- **Responder-level resolution counts aren't available** — PagerDuty's responder analytics API reports involvement (incident count, interruptions, acknowledgements, on-call time, mean time to resolve) but not how many incidents each responder actually resolved. For per-incident resolution attribution, use the **Incidents** stream's **Modified By** column, filtered to Status = Resolved. +- **Notifications are capped at a 3-month window** — the **Notifications** stream's timeframe options stop at "Last month". +- **Teams require an add-on account ability** — the **Teams** import step (and the Team scope/dashboards it feeds) only returns data on PagerDuty plans with the Teams ability enabled. On accounts without it, PagerDuty rejects the request and the step is skipped with a warning rather than failing the whole import — everything else (Services, Users, Schedules, Escalation Policies, Incidents, etc.) still imports and refreshes normally. +- **Notifications' User filter is applied client-side** — PagerDuty's notifications endpoint has no server-side user filter, so the plugin fetches the full window and filters by user in the plugin itself. This is transparent to you, but very high notification volumes over a wide timeframe may be slower to filter than a server-side filter would be. +- **No direct Team → Service/User relationship** — the PagerDuty API only lists services/users *with* their team IDs, not teams *with* their members, so the Team perspective shows incidents and responder metrics for a team but not a services/users roster. +- **Rate limits** — PagerDuty enforces per-account API rate limits; very large estates may import or refresh more slowly. +- **Read-only** — the plugin never creates, modifies, or deletes anything in PagerDuty. diff --git a/plugins/PagerDuty/v2/icon.svg b/plugins/PagerDuty/v2/icon.svg new file mode 100644 index 00000000..3be364b5 --- /dev/null +++ b/plugins/PagerDuty/v2/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/plugins/PagerDuty/v2/indexDefinitions/default.json b/plugins/PagerDuty/v2/indexDefinitions/default.json new file mode 100644 index 00000000..72ab7383 --- /dev/null +++ b/plugins/PagerDuty/v2/indexDefinitions/default.json @@ -0,0 +1,67 @@ +{ + "steps": [ + { + "name": "services", + "dataStream": { "name": "services" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "PagerDuty Service" }, + "properties": [ + "status", + "description", + "escalationPolicyId", + "escalationPolicyName", + "teamIds", + "teamNames" + ] + } + }, + { + "name": "users", + "dataStream": { "name": "users" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "PagerDuty User" }, + "properties": ["email", "role", "jobTitle", "timezone", "teamIds", "teamNames"] + } + }, + { + "name": "teams", + "dataStream": { "name": "teams" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "PagerDuty Team" }, + "properties": ["description"] + }, + "optional": true + }, + { + "name": "schedules", + "dataStream": { "name": "schedules" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "PagerDuty Schedule" }, + "properties": [{ "timezone": "time_zone" }, "description"] + } + }, + { + "name": "escalationPolicies", + "dataStream": { "name": "escalationPolicies" }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { "value": "PagerDuty Escalation Policy" }, + "properties": [{ "numLoops": "num_loops" }, "teamIds", "teamNames"] + } + } + ] +} diff --git a/plugins/PagerDuty/v2/metadata.json b/plugins/PagerDuty/v2/metadata.json new file mode 100644 index 00000000..9f72518c --- /dev/null +++ b/plugins/PagerDuty/v2/metadata.json @@ -0,0 +1,39 @@ +{ + "name": "pagerduty", + "displayName": "PagerDuty", + "version": "2.0.0", + "author": { "name": "@vinbab", "type": "community" }, + "description": "Visualize and monitor PagerDuty incidents, services, on-call schedules and responder performance in SquaredUp.", + "category": "Alert Management", + "type": "hybrid", + "schemaVersion": "2.1", + "importNotSupported": false, + "restrictedToPlatforms": [], + "keywords": ["pagerduty", "incident management", "on-call", "alerting", "incident response"], + "objectTypes": ["PagerDuty Service", "PagerDuty User", "PagerDuty Team", "PagerDuty Schedule", "PagerDuty Escalation Policy"], + "links": [ + { + "category": "documentation", + "url": "https://github.com/squaredup/plugins/blob/main/plugins/PagerDuty/v2/docs/README.md", + "label": "Help adding this plugin" + }, + { + "category": "source", + "url": "https://github.com/squaredup/plugins/tree/main/plugins/PagerDuty/v2", + "label": "Repository" + } + ], + "base": { + "plugin": "WebAPI", + "majorVersion": "1", + "config": { + "baseUrl": "{{region === 'eu' ? 'https://api.eu.pagerduty.com' : 'https://api.pagerduty.com'}}", + "authMode": "none", + "headers": [ + { "key": "Authorization", "value": "Token token={{apiToken}}" }, + { "key": "Accept", "value": "application/vnd.pagerduty+json;version=2" } + ], + "queryArgs": [{ "key": "time_zone", "value": "{{timezone}}" }] + } + } +} diff --git a/plugins/PagerDuty/v2/ui.json b/plugins/PagerDuty/v2/ui.json new file mode 100644 index 00000000..b1ad0426 --- /dev/null +++ b/plugins/PagerDuty/v2/ui.json @@ -0,0 +1,30 @@ +[ + { + "type": "password", + "name": "apiToken", + "label": "API token", + "help": "A PagerDuty REST API key. Use a personal token, or a general-access token if you want it to survive your account being removed.", + "placeholder": "Enter an API token", + "validation": { "required": true } + }, + { + "type": "radio", + "name": "region", + "label": "Service region", + "help": "The PagerDuty service region your account is hosted in. Check your account settings if you're not sure.", + "defaultValue": "us", + "options": [ + { "value": "us", "label": "Global/US (api.pagerduty.com)" }, + { "value": "eu", "label": "EU (api.eu.pagerduty.com)" } + ], + "validation": { "required": true } + }, + { + "type": "text", + "name": "timezone", + "label": "Timezone", + "help": "IANA timezone used to align time-based filters and aggregations (e.g. `America/New_York`, `Europe/London`). Defaults to UTC.", + "defaultValue": "Etc/UTC", + "placeholder": "Etc/UTC" + } +]