Merge branch 'dev' into web-schedules-fixes-bunch-3

This commit is contained in:
Maxim 2022-11-04 14:27:43 +00:00
commit 59cd574e25
60 changed files with 1146 additions and 852 deletions

View file

@ -1,5 +1,11 @@
# Change Log
## v1.0.50 (2022-11-03)
- Updates to documentation
- Improvements to web schedules
- Bug fixes
## v1.0.49 (2022-11-01)
- Enable SMTP email backend by default

View file

@ -8,4 +8,4 @@ pull:
.PHONY: docs
docs: pull
docker run -v '$(shell pwd)/sources:$(CONTENT_PATH):Z' -p $(PORT) --rm -it $(IMAGE)
docker run -v '$(shell pwd)/sources:$(CONTENT_PATH):Z' -v '$(shell pwd)/sources:/jugo/content/docs/grafana-cloud/oncall:Z' -p $(PORT) --rm -it $(IMAGE)

View file

@ -1,7 +1,7 @@
---
aliases:
- /docs/grafana-cloud/oncall/
- /docs/oncall/latest/
canonical: https://grafana.com/docs/oncall/latest/
keywords:
- Grafana Cloud
- Alerts
@ -11,7 +11,6 @@ keywords:
- OnCall
- irm
title: Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/"
weight: 1000
---
@ -22,7 +21,7 @@ weight: 1000
Grafana OnCall is an open source incident response management tool built to help teams improve their collaboration and resolve incidents faster. Some of the core strengths of Grafana OnCall include:
- **Support for a broad set of monitoring systems:** Grafana OnCall supports integrations with many monitoring systems, including Grafana, Prometheus, AlertManager, Zabbix, and more.
- **Support for a broad set of monitoring systems:** Grafana OnCall supports integrations with many monitoring systems, including Grafana, Prometheus, Alertmanager, Zabbix, and more.
- **Reduce alert noise:** Automatic alert grouping helps avoid alert storms and reduce noise during incidents. Auto-resolve settings can resolve without human intervention when the resolve conditions are met, enabling you to control alert noise and reduce alert fatigue.
- **Automatic escalation to on-call rotations:** Grafana OnCalls flexible calendar integration allows you to define your on-call rotations while managing on-call schedules in your preferred calendar application with iCal format. Configurable alert escalation automatically escalates alerts to on-call team members, notifies slack channels, and more.
- **ChatOps focused:** Grafana OnCall integrates closely with your slack workspace to deliver alert notifications to individuals and groups, making daily alerts more visible and easier to manage.
@ -30,6 +29,4 @@ Grafana OnCall is an open source incident response management tool built to help
- **Massive scalability:** Grafana OnCall is equipped with a full API and Terraform capabilities. Ready for GitOps and large organization configuration.
> **Note:** You can use [Grafana Cloud](https://grafana.com/products/cloud/?plcmt=nav-products-cta1&cta=cloud) to avoid installing, maintaining, and scaling your own instance of Grafana OnCall. The free forever plan includes 30 Grafana OnCall notification. [Create an account to get started](https://grafana.com/auth/sign-up/create-user?pg=oncall&plcmt=hero-btn-1).
{{< section >}}

View file

@ -0,0 +1,23 @@
---
aliases:
- /docs/oncall/latest/alert-behavior/
canonical: https://grafana.com/docs/oncall/latest/alert-behavior/
title: Configure alert behavior for Grafana OnCall
weight: 900
---
# Configure alert behavior for Grafana OnCall
The available alert configurations in Grafana OnCall allow you to define how certain alerts are handled and ensure that alerts are routed, escalated, and grouped to fit your specific alerting needs. Grafana OnCall can receive alerts from any monitoring system that sends alerts via webhook.
## About alert behavior
Once Grafana OnCall receives an alert, the following occurs, based on the alert content:
- Default or customized alert templates are applied to deliver the most useful alert fields with the most valuable information, in a readable format.
- Alerts are grouped based on your alert grouping configurations, combining similar or related alerts to reduce alert noise.
- Alerts automatically resolve if an alert from the monitoring system matches the resolve condition for that alert.
{{< section >}}

View file

@ -1,18 +1,19 @@
---
aliases:
- /docs/oncall/latest/integrations/create-custom-templates/
- ../integrations/create-custom-templates/
- /docs/oncall/latest/alert-behavior/alert-templates/
canonical: https://grafana.com/docs/oncall/latest/alert-behavior/alert-templates/
keywords:
- Grafana Cloud
- Alerts
- Notifications
- on-call
- Jinja
title: Configure alerts in Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/create-custom-templates/"
title: Configure alert templates
weight: 300
---
# Configure alerts in Grafana OnCall
# Configure alert templates
Grafana OnCall can integrate with any monitoring systems that can send alerts using webhooks with JSON payloads. By default, webhooks deliver raw JSON payloads. When Grafana OnCall receives an alert and parses its payload, a default pre configured alert template is applied to modify the alert payload to be more human readable. These alert templates are customizable for any integration.

View file

@ -1,6 +1,8 @@
---
aliases:
- /docs/oncall/latest/integrations/configure-outgoing-webhooks/
- ../integrations/configure-outgoing-webhooks/
- /docs/oncall/latest/alert-behavior/outgoing-webhooks/
canonical: https://grafana.com/docs/oncall/latest/alert-behavior/outgoing-webhooks/
keywords:
- Grafana Cloud
- Alerts
@ -9,7 +11,6 @@ keywords:
- amixr
- webhooks
title: Configure outgoing webhooks for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/configure-outgoing-webhooks/"
weight: 500
---

View file

@ -1,6 +1,7 @@
---
aliases:
- /docs/oncall/latest/calendar-schedules/
canonical: https://grafana.com/docs/oncall/latest/calendar-schedules/
description: ""
keywords:
- Grafana
@ -8,7 +9,6 @@ keywords:
- on-call
- calendar
title: Configure and manage on-call schedules
canonical: "https://grafana.com/docs/oncall/latest/calendar-schedules/"
weight: 1100
---

View file

@ -1,6 +1,7 @@
---
aliases:
- /docs/oncall/latest/configure-user-settings/
canonical: https://grafana.com/docs/oncall/latest/configure-user-setting/
keywords:
- Grafana Cloud
- Alerts
@ -10,7 +11,6 @@ keywords:
- oncall
- integrations
title: Manage users and teams for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/configure-user-setting/"
weight: 1300
---

View file

@ -1,13 +1,12 @@
---
title: Configure escalation chains and routes for Grafana OnCall
weight: 700
canonical: "https://grafana.com/docs/oncall/latest/escalation-policies/"
aliases:
- /docs/oncall/latest/chat-options/escalation-policies/
- /docs/oncall/latest/escalation-policies/
canonical: https://grafana.com/docs/oncall/latest/escalation-policies/
title: Escalation Chains and Routes
weight: 700
---
# Configure escalation chains and routes for Grafana OnCall
# Escalation Chains and Routes
Escalation chains and routes for Grafana OnCall

View file

@ -1,6 +1,7 @@
---
aliases:
- /docs/oncall/latest/escalation-policies/configure-escalation-chains/
canonical: https://grafana.com/docs/oncall/latest/escalation-policies/configure-escalation-chains/
keywords:
- Grafana Cloud
- Alerts
@ -10,7 +11,6 @@ keywords:
- oncall
- integrations
title: Configure and manage Escalation Chains
canonical: "https://grafana.com/docs/oncall/latest/escalation-policies/configure-escalation-chains/"
weight: 100
---

View file

@ -1,6 +1,7 @@
---
aliases:
- /docs/oncall/latest/escalation-policies/configure-routes/
canonical: https://grafana.com/docs/oncall/latest/escalation-policies/configure-routes/
keywords:
- Grafana Cloud
- Alerts
@ -10,11 +11,10 @@ keywords:
- oncall
- integrations
title: Configure and manage routes
canonical: "https://grafana.com/docs/oncall/latest/escalation-policies/configure-routes/"
weight: 300
---
# Configure and manage routes
# Configure and manage Routes
Set up escalation chains and routes to configure escalation behavior for alert group notifications.

View file

@ -1,13 +1,13 @@
---
aliases:
- /docs/grafana-cloud/oncall/getting-started/
- /docs/oncall/latest/getting-started/
- /docs/oncall/latest/get-started/
- /getting-started/
canonical: https://grafana.com/docs/oncall/latest/get-started/
keywords:
- Get started
- On call
- Grafana Cloud
title: Get started with Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/getting-started/"
weight: 300
---
@ -26,10 +26,7 @@ These procedures introduce you to initial Grafana OnCall configuration steps, in
## Before you begin
Grafana OnCall is available for Grafana Cloud as well as Grafana open source users. You must have a Grafana Cloud account or [Open Source Grafana OnCall]({{< relref "../open-source" >}})
For more information, see [Grafana Pricing](https://grafana.com/pricing/) for details.
Grafana OnCall is available for Grafana Cloud as well as Grafana open source users. You must have a Grafana Cloud account or use [Open Source Grafana OnCall]({{< relref "../open-source" >}})
## Install Open Source Grafana OnCall
@ -59,7 +56,7 @@ Regardless of where your alerts originate, you can send them to Grafana OnCall v
2. Explore the alert by clicking on the title of the alert.
3. Acknowledge and resolve the test alert.
For more information on Grafana OnCall integrations and further configuration guidance, refer to, [Connect to Grafana OnCall]({{< relref "../integrations" >}})
For more information on Grafana OnCall integrations and further configuration guidance, refer to, [Grafana OnCall integrations]({{< relref "../integrations" >}})
### Configure Escalation Chains
@ -105,7 +102,7 @@ To configure Slack for Grafana OnCall:
5. Click Allow to allow Grafana OnCall to access Slack.
6. Ensure users verify their Slack accounts in their user profile in Grafana OnCall.
For further instruction on connecting to your Slack workspace, refer to [Connect Slack to Grafana OnCall]({{< relref "../chat-options/configure-slack" >}})
For further instruction on connecting to your Slack workspace, refer to [Slack integration for Grafana OnCall]({{< relref "../integrations/chatops-integrations/configure-slack/" >}})
### Add your on-call schedule

View file

@ -1,7 +1,7 @@
---
aliases:
- /docs/grafana-cloud/oncall/integrations/
- /docs/oncall/latest/integrations/
canonical: https://grafana.com/docs/oncall/latest/integrations/
keywords:
- Grafana Cloud
- Alerts
@ -10,12 +10,11 @@ keywords:
- amixr
- oncall
- integrations
title: Connect to Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/"
title: Grafana OnCall integrations
weight: 500
---
# Connect to Grafana OnCall
# Grafana OnCall integrations
Integrations allow you to connect monitoring systems of your choice to send alerts to Grafana OnCall. Regardless of where your alerts originate, you can configure alerts to be sent to Grafana OnCall for alert escalation and notification. Grafana OnCall receives alerts in JSON format via a POST request, OnCall then parses alert data using preconfigured alert templates to determine alert grouping, apply routes, and determine correct escalation.
@ -53,7 +52,7 @@ To customize alert grouping for an integration:
2. Select **Alert Behavior** from the dropdown menu next to **Edit template for**.
3. Edit the **grouping id**, **acknowledge condition**, and **resolve condition** templates as needed to customize your alert behavior.
For more information on alert templates, see [Configure alerts in Grafana OnCall]({{< relref "create-custom-templates/" >}})
For more information on alert templates, see [Configure alerts templates]({{< relref "../alert-behavior/alert-templates" >}})
#### Add Routes

View file

@ -1,7 +1,7 @@
---
aliases:
- /docs/grafana-cloud/oncall/integrations/add-integration/
- /docs/oncall/latest/integrations/available-integrations/
canonical: https://grafana.com/docs/oncall/latest/integrations/available-integrations/
keywords:
- Grafana Cloud
- Alerts
@ -10,15 +10,14 @@ keywords:
- Alertmanager
- Prometheus
title: Currently available integrations for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/available-integrations/"
weight: 100
---
# Currently available integrations
# Available integrations
Grafana OnCall can connect directly to the monitoring services where your alerts originate. All currently available integrations are listed in the Grafana OnCall **Create Integration** section.
If the integration you're looking for isn't currently listed, see [Configure Webhook integrations for Grafana OnCall]({{< relref "../add-webhook-integration/" >}}) to integration your monitoring system with Grafana OnCall.
If the integration you're looking for isn't currently listed, see [Webhook integrations for Grafana OnCall]({{< relref "../available-integrations/configure-webhook" >}}) to integration your monitoring system with Grafana OnCall.
> **Note:** Some integrations are available for Grafana Cloud instances only. See individual integration guides for more information.

View file

@ -1,7 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/available-integrations/add-alertmanager/
- /docs/oncall/latest/integrations/available-integrations /add-alertmanager/
- add-alertmanager/
- /docs/oncall/latest/integrations/available-integrations/configure-alertmanager/
canonical: https://grafana.com/docs/oncall/latest/integrations/available-integrations/configure-alertmanager/
keywords:
- Grafana Cloud
- Alerts
@ -9,12 +10,11 @@ keywords:
- on-call
- Alertmanager
- Prometheus
title: Connect Alertmanager to Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/available-integrations/add-alertmanager/"
title: Alertmanager integration for Grafana OnCall
weight: 300
---
# Connect Alertmanager to Grafana OnCall
# Alertmanager integration for Grafana OnCall
The Alertmanager integration for Grafana OnCall handles alerts sent by client applications such as the Prometheus server.

View file

@ -1,19 +1,19 @@
---
aliases:
- /docs/grafana-cloud/oncall/integrations/add-grafana-alerting/
- /docs/oncall/latest/integrations/available-integrations /add-grafana-alerting/
- add-grafana-alerting/
- /docs/oncall/latest/integrations/available-integrations/configure-grafana-alerting/
canonical: https://grafana.com/docs/oncall/latest/integrations/available-integrations/configure-grafana-alerting/
keywords:
- Grafana Cloud
- Alerts
- Notifications
- on-call
- Prometheus
title: Connect Grafana Alerting to Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/available-integrations/add-grafana-alerting/"
title: Grafana Alerting integration for Grafana OnCall
weight: 100
---
# Connect Grafana Alerting to Grafana OnCall
# Grafana Alerting integration for Grafana OnCall
Grafana Alerting for Grafana OnCall can be set up using two methods:

View file

@ -1,6 +1,8 @@
---
aliases:
- /docs/oncall/latest/integrations/add-webhook-integration/
- ../add-webhook-integration/
- /docs/oncall/latest/integrations/available-integrations/configure-webhook/
canonical: https://grafana.com/docs/oncall/latest/integrations/available-integrations/configure-webhook/
keywords:
- Grafana Cloud
- Alerts
@ -9,11 +11,10 @@ keywords:
- Alertmanager
- Prometheus
title: Webhook integration for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/add-webhook-integration/"
weight: 700
---
# Configure Webhook integrations for Grafana OnCall
# Webhook integrations for Grafana OnCall
Grafana OnCall directly supports many integrations, those that arent currently listed in the Integrations menu can be connected using the webhook integration and configured alert templates.
@ -56,4 +57,4 @@ For example:
}'
```
To learn how to use custom alert templates for formatted webhooks, see [Configure alerts in Grafana OnCall]({{< relref "../integrations/create-custom-templates/" >}}).
To learn how to use custom alert templates for formatted webhooks, see [Configure alerts templates]({{< relref "../../../alert-behavior/alert-templates/" >}}).

View file

@ -1,18 +1,19 @@
---
aliases:
- /docs/oncall/latest/integrations/available-integrations /add-zabbix/
- add-zabbix/
- /docs/oncall/latest/integrations/available-integrations/configure-zabbix/
canonical: https://grafana.com/docs/oncall/latest/integrations/available-integrations/configure-zabbix/
keywords:
- Grafana Cloud
- Alerts
- Notifications
- on-call
- Zabbix
title: Connect Zabbix to Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/integrations/available-integrations/add-zabbix/"
title: Zabbix integration for Grafana OnCall
weight: 500
---
# Connect Zabbix to Grafana OnCall
# Zabbix integration for Grafana OnCall
Zabbix is an open-source monitoring software tool for diverse IT components, including networks, servers, virtual machines, and cloud services. Zabbix provides monitoring for metrics such as network utilization, CPU load, and disk space consumption.

View file

@ -1,6 +1,8 @@
---
aliases:
- /docs/oncall/latest/chat-options/
- ../chat-options/
- /docs/oncall/latest/integrations/chatops-integrations/
canonical: https://grafana.com/docs/oncall/latest/integrations/chatops-integrations/
keywords:
- Grafana Cloud
- Alerts
@ -9,14 +11,13 @@ keywords:
- amixr
- oncall
- slack
title: Connect ChatOps to Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/chat-options/"
weight: 900
title: Available ChatOps integrations
weight: 300
---
# Connect ChatOps to Grafana OnCall
# Available ChatOps integrations
Grafana OnCall directly supports the export of alert notifications to some popular messaging applications like Slack and Telegram. You can use outgoing webhooks to applications that aren't directly supported. For information on configuring outgoing webhooks, see [Send alert group notifications by webhook]({{< relref "../integrations/configure-outgoing-webhooks.md" >}}).
Grafana OnCall directly supports the export of alert notifications to some popular messaging applications like Slack and Telegram. You can use outgoing webhooks to applications that aren't directly supported. For information on configuring outgoing webhooks, see [Send alert group notifications by webhook]({{< relref "../../alert-behavior/outgoing-webhooks/" >}}).
To configure supported messaging apps, see the following topics:

View file

@ -1,6 +1,8 @@
---
aliases:
- /docs/oncall/latest/chat-options/configure-slack/
- ../../chat-options/configure-slack/
- /docs/oncall/latest/integrations/chatops-integrations/configure-slack/
canonical: https://grafana.com/docs/oncall/latest/integrations/chatops-integrations/configure-slack/
keywords:
- Grafana Cloud
- Alerts
@ -10,7 +12,6 @@ keywords:
- oncall
- slack
title: Slack integration for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/chat-options/configure-slack/"
weight: 100
---
@ -25,7 +26,7 @@ Integrating your Slack workspace with Grafana OnCall allows users and teams to b
To install the Slack integration, you must have Admin permissions in your Grafana instance as well as the Slack workspace that youd like to integrate with.
For Open Source Grafana OnCall Slack installation guidance, refer to [Open Source Grafana OnCall]({{< relref "../open-source" >}}).
For Open Source Grafana OnCall Slack installation guidance, refer to [Open Source Grafana OnCall]({{< relref "../../../open-source/" >}}).
## Install Slack integration for Grafana OnCall

View file

@ -1,6 +1,8 @@
---
aliases:
- /docs/oncall/latest/chat-options/configure-teams/
- ../../chat-options/configure-teams/
- /docs/oncall/latest/integrations/chatops-integrations/configure-teams/
canonical: https://grafana.com/docs/oncall/latest/integrations/chatops-integrations/configure-teams/
keywords:
- Grafana Cloud
- Alerts
@ -11,7 +13,6 @@ keywords:
- MS Team
- Microsoft
title: Microsoft Teams integration for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/chat-options/configure-teams/"
weight: 500
---

View file

@ -1,6 +1,8 @@
---
aliases:
- /docs/oncall/latest/chat-options/configure-telegram/
- ../../chat-options/configure-telegram/
- /docs/oncall/latest/integrations/chatops-integrations/configure-telegram/
canonical: https://grafana.com/docs/oncall/latest/integrations/chatops-integrations/configure-telegram/
keywords:
- Grafana Cloud
- Alerts
@ -10,7 +12,6 @@ keywords:
- oncall
- telegram
title: Telegram integration for Grafana OnCall
canonical: "https://grafana.com/docs/oncall/latest/chat-options/configure-telegram/"
weight: 300
---

View file

@ -1,8 +1,8 @@
---
aliases:
- /docs/oncall/latest/oncall-api-reference/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/
title: Grafana OnCall HTTP API reference
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/"
weight: 1500
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/alertgroups/
- /docs/oncall/latest/oncall-api-reference/alertgroups/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/alertgroups/
title: Alert groups HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/alertgroups/"
weight: 400
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/alerts/
- /docs/oncall/latest/oncall-api-reference/alerts/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/alerts/
title: Alerts HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/alerts/"
weight: 100
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/escalation_chains/
- /docs/oncall/latest/oncall-api-reference/escalation_chains/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/escalation_chains/
title: Escalation Chains HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/escalation_chains/"
weight: 200
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/escalation_policies/
- /docs/oncall/latest/oncall-api-reference/escalation_policies/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/escalation_policies/
title: Escalation Policies HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/escalation_policies/"
weight: 300
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/integrations/
- /docs/oncall/latest/oncall-api-reference/integrations/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/integrations/
title: Integrations HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/integrations/"
weight: 500
---
@ -68,7 +67,7 @@ The above command returns JSON structured in the following way:
```
Integrations are sources of alerts and alert groups for Grafana OnCall.
For example, to learn how to integrate Grafana OnCall with Alertmanager see [Alertmanager]({{< relref "../integrations/available-integrations/add-alertmanager/" >}}).
For example, to learn how to integrate Grafana OnCall with Alertmanager see [Alertmanager]({{< relref "../integrations/available-integrations/configure-alertmanager/" >}}).
**HTTP request**

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/on_call_shifts/
- /docs/oncall/latest/oncall-api-reference/on_call_shifts/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/on_call_shifts/
title: OnCall shifts HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/on_call_shifts/"
weight: 600
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/outgoing_webhooks/
- /docs/oncall/latest/oncall-api-reference/outgoing_webhooks/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/outgoing_webhooks/
title: Outgoing webhooks HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/outgoing_webhooks/"
weight: 700
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/personal_notification_rules/
- /docs/oncall/latest/oncall-api-reference/personal_notification_rules/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/personal_notification_rules/
title: Personal Notification Rules HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/personal_notification_rules/"
weight: 800
---

View file

@ -1,10 +1,9 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/postmortem_messages/
- /docs/oncall/latest/oncall-api-reference/postmortem_messages/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/postmortem_messages/
draft: true
title: Postmortem Messages HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/postmortem_messages/"
weight: 900
---

View file

@ -1,10 +1,9 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/postmortems/
- /docs/oncall/latest/oncall-api-reference/postmortems/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/postmortems/
draft: true
title: Postmortem HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/postmortems/"
weight: 1000
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/routes/
- /docs/oncall/latest/oncall-api-reference/routes/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/routes/
title: Routes HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/routes/"
weight: 1100
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/schedules/
- /docs/oncall/latest/oncall-api-reference/schedules/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/schedules/
title: Schedule HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/schedules/"
weight: 1200
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/slack_channels/
- /docs/oncall/latest/oncall-api-reference/slack_channels/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/slack_channels/
title: Slack Channels HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/slack_channels/"
weight: 1300
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/user_groups/
- /docs/oncall/latest/oncall-api-reference/user_groups/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/user_groups/
title: OnCall User Groups HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/user_groups/"
weight: 1400
---

View file

@ -1,9 +1,8 @@
---
aliases:
- /docs/grafana-cloud/oncall/oncall-api-reference/users/
- /docs/oncall/latest/oncall-api-reference/users/
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/users/
title: Grafana OnCall Users HTTP API
canonical: "https://grafana.com/docs/oncall/latest/oncall-api-reference/users/"
weight: 1500
---

View file

@ -1,6 +1,5 @@
---
aliases:
- /docs/grafana-cloud/oncall/open-source/
- /docs/oncall/latest/open-source/
keywords:
- Open Source

View file

@ -1,4 +1,4 @@
FROM python:3.9-alpine
FROM python:3.9-alpine3.16
RUN apk add bash python3-dev build-base linux-headers pcre-dev mariadb-connector-c-dev openssl-dev libffi-dev git
RUN pip install uwsgi

View file

@ -277,31 +277,44 @@ class CustomOnCallShift(models.Model):
return is_finished
def _daily_by_day_to_ical(self, time_zone, start, users_queue):
"""Create ical weekly shifts to distribute user groups combining daily + by_day."""
"""Create ical weekly shifts to distribute user groups combining daily + by_day.
e.g.
by_day: [WED, FRI]
users_queue: [user_group_1, user_group_2, user_group_3]
will result in the following ical shift rules:
user_group_1, weekly WED interval 3
user_group_2, weekly FRI interval 3
user_group_3, weekly WED interval 3
user_group_1, weekly FRI interval 3
user_group_2, weekly WED interval 3
user_group_3, weekly FRI interval 3
"""
result = ""
# keep tracking of (users, day) combinations, and starting dates for each
combinations = []
starting_dates = []
# we may need to iterate several times over users until we get a seen combination
cycle_users = itertools.cycle(users_queue)
# use the group index as reference since user groups could repeat in the queue
cycle_user_groups = itertools.cycle(range(len(users_queue)))
orig_start = last_start = start
all_rotations_checked = False
# we need to go through each individual day
day_by_day_rrule = copy.deepcopy(self.event_ical_rules)
day_by_day_rrule["interval"] = 1
for users in cycle_users:
for user_group_id in cycle_user_groups:
for i in range(self.interval):
if not start: # means that rotation ends before next event starts
all_rotations_checked = True
break
last_start = start
day = CustomOnCallShift.ICAL_WEEKDAY_MAP[start.weekday()]
if (users, day, i) in combinations:
if (user_group_id, day, i) in combinations:
all_rotations_checked = True
break
starting_dates.append(start)
combinations.append((users, day, i))
combinations.append((user_group_id, day, i))
# get next event date following the original rule
event_ical = self.generate_ical(start, 1, None, 1, time_zone, custom_rrule=day_by_day_rrule)
start = self.get_rotation_date(event_ical, get_next_date=True, interval=1)
@ -311,7 +324,8 @@ class CustomOnCallShift(models.Model):
# number of weeks used to cover all combinations
week_interval = ((last_start - orig_start).days // 7) or 1
counter = 1
for ((users, day, _), start) in zip(combinations, starting_dates):
for ((user_group_id, day, _), start) in zip(combinations, starting_dates):
users = users_queue[user_group_id]
for user_counter, user in enumerate(users, start=1):
# setup weekly events, for each user group/day combinations,
# setting the right interval and the corresponding day

View file

@ -227,7 +227,7 @@ class OnCallSchedule(PolymorphicModel):
end = shift["end"] - timezone.timedelta(days=1) if all_day else shift["end"]
if all_day and all_day_datetime:
start = datetime.datetime.combine(start, datetime.datetime.min.time(), tzinfo=pytz.UTC)
end = datetime.datetime.combine(start, datetime.datetime.max.time(), tzinfo=pytz.UTC)
end = datetime.datetime.combine(end, datetime.datetime.max.time(), tzinfo=pytz.UTC)
is_gap = shift.get("is_gap", False)
shift_json = {
"all_day": all_day,

View file

@ -30,6 +30,20 @@ SUMMARY:@Alex
TRANSP:TRANSPARENT
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20210127
DTEND;VALUE=DATE:20210129
DTSTAMP:20210127T154139Z
UID:7q00jpu4hdlr9e3j4fftbv7kt8@google.com
CREATED:20210127T143802Z
DESCRIPTION:
LAST-MODIFIED:20210127T143802Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:@Alice
TRANSP:TRANSPARENT
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=Asia/Yekaterinburg:20210127T130000
DTEND;TZID=Asia/Yekaterinburg:20210127T220000
DTSTAMP:20210127T154139Z

View file

@ -45,8 +45,9 @@ def test_recurring_ical_events_with_all_day_event(get_ical):
parsed_iso_day_to_check - timezone.timedelta(days=1),
parsed_iso_day_to_check + timezone.timedelta(days=1),
)
assert len(events) == 4
assert len(events) == 5
assert events[0]["SUMMARY"] == "@Alex"
assert events[1]["SUMMARY"] == "@Bob"
assert events[2]["SUMMARY"] == "@Bernard Desruisseaux"
assert events[1]["SUMMARY"] == "@Alice"
assert events[2]["SUMMARY"] == "@Bob"
assert events[3]["SUMMARY"] == "@Bernard Desruisseaux"
assert events[4]["SUMMARY"] == "@Bernard Desruisseaux"

View file

@ -91,7 +91,7 @@ def test_shifts_dict_all_day_middle_event(make_organization, make_schedule, get_
parsed_iso_day_to_check = datetime.datetime.fromisoformat(day_to_check_iso).replace(tzinfo=pytz.UTC)
requested_date = (parsed_iso_day_to_check - timezone.timedelta(days=1)).date()
shifts = list_of_oncall_shifts_from_ical(schedule, requested_date, days=3, with_empty_shifts=True)
assert len(shifts) == 4
assert len(shifts) == 5
for s in shifts:
start = s["start"].date() if isinstance(s["start"], datetime.datetime) else s["start"]
end = s["end"].date() if isinstance(s["end"], datetime.datetime) else s["end"]

View file

@ -235,7 +235,7 @@ def test_filter_events_ical_all_day(make_organization, make_user_for_organizatio
organization = make_organization()
schedule = make_schedule(organization, schedule_class=OnCallScheduleCalendar)
schedule.cached_ical_file_primary = calendar.to_ical()
for u in ("@Bernard Desruisseaux", "@Bob", "@Alex"):
for u in ("@Bernard Desruisseaux", "@Bob", "@Alex", "@Alice"):
make_user_for_organization(organization, username=u)
# clear users pks <-> organization cache (persisting between tests)
memoized_users_in_ical.cache_clear()
@ -259,6 +259,12 @@ def test_filter_events_ical_all_day(make_organization, make_user_for_organizatio
datetime.datetime(2021, 1, 27, 0, 0, tzinfo=pytz.UTC),
datetime.datetime(2021, 1, 27, 23, 59, 59, 999999, tzinfo=pytz.UTC),
),
(
True,
["@Alice"],
datetime.datetime(2021, 1, 27, 0, 0, tzinfo=pytz.UTC),
datetime.datetime(2021, 1, 28, 23, 59, 59, 999999, tzinfo=pytz.UTC),
),
(
False,
["@Bob"],

View file

@ -1,4 +1,4 @@
django==3.2.15
django==3.2.16
djangorestframework==3.12.4
slackclient==1.3.0
whitenoise==5.3.0

View file

@ -101,6 +101,7 @@ CELERY_TASK_ROUTES = {
"apps.alerts.tasks.unsilence.unsilence_task": {"queue": "critical"},
"apps.base.tasks.process_failed_to_invoke_celery_tasks": {"queue": "critical"},
"apps.base.tasks.process_failed_to_invoke_celery_tasks_batch": {"queue": "critical"},
"apps.email.tasks.notify_user_async": {"queue": "critical"},
"apps.integrations.tasks.create_alert": {"queue": "critical"},
"apps.integrations.tasks.create_alertmanager_alerts": {"queue": "critical"},
"apps.integrations.tasks.start_notify_about_integration_ratelimit": {"queue": "critical"},

View file

@ -0,0 +1,15 @@
{
"presets": [
["@babel/preset-env", { "targets": { "node": "current" } }],
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-transform-destructuring", { "useBuiltIns": true }],
"@babel/plugin-transform-runtime",
"@babel/proposal-class-properties",
"@babel/transform-regenerator",
"@babel/plugin-transform-template-literals",
]
}

View file

@ -1,29 +1,19 @@
const esModules = ['react-colorful', 'uuid', 'ol'].join('|');
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleDirectories: ['node_modules', 'src'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
moduleFileExtensions: ['ts', 'tsx', 'js'],
globals: {
'ts-jest': {
isolatedModules: true,
babelConfig: true
},
},
transform: {
'^.+\\.js?$': require.resolve('babel-jest'),
'^.+\\.jsx?$': require.resolve('babel-jest'),
'^.+\\.ts?$': require.resolve('ts-jest'),
'^.+\\.tsx?$': require.resolve('ts-jest'),
},
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
moduleNameMapper: {
"grafana/app/(.*)": '<rootDir>/src/jest/grafanaMock.ts',
"jest/outgoingWebhooksStub": '<rootDir>/src/jest/outgoingWebhooksStub.ts',
"^jest$": '<rootDir>/src/jest',
'grafana/app/(.*)': '<rootDir>/src/jest/grafanaMock.ts',
'jest/matchMedia': '<rootDir>/src/jest/matchMedia.ts',
'jest/outgoingWebhooksStub': '<rootDir>/src/jest/outgoingWebhooksStub.ts',
'^jest$': '<rootDir>/src/jest',
'^.+\\.(css|scss)$': '<rootDir>/src/jest/styleMock.ts',
"^lodash-es$": "lodash",
}
};
'^lodash-es$': 'lodash',
},
};

View file

@ -40,27 +40,29 @@
"license": "Apache-2.0",
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.18.10",
"@babel/plugin-proposal-decorators": "^7.20.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
"@babel/plugin-syntax-decorators": "^7.18.6",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-destructuring": "^7.20.0",
"@babel/plugin-transform-react-constant-elements": "^7.18.12",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/plugin-transform-typescript": "^7.18.12",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@grafana/data": "^9.1.1",
"@grafana/data": "9.1.1",
"@grafana/eslint-config": "^5.0.0",
"@grafana/runtime": "^9.1.1",
"@grafana/toolkit": "^9.1.1",
"@grafana/ui": "^9.1.1",
"@jest/globals": "^27.5.1",
"@grafana/runtime": "9.1.1",
"@grafana/toolkit": "9.1.1",
"@grafana/ui": "9.1.1",
"@jest/globals": "27.5.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "12",
"@types/dompurify": "^2.3.4",
"@types/jest": "^27.5.1",
"@types/jest": "27.5.1",
"@types/lodash-es": "^4.17.6",
"@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-dom": "^18.0.6",
@ -69,6 +71,7 @@
"@types/react-test-renderer": "^17.0.2",
"@types/throttle-debounce": "^5.0.0",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"babel-plugin-dynamic-import-node": "^2.3.3",
"copy-webpack-plugin": "^11.0.0",
"dompurify": "^2.3.12",
"eslint": "^8.25.0",
@ -76,17 +79,19 @@
"eslint-plugin-react": "^7.31.10",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-rulesdir": "^0.2.1",
"jest": "^27.5.1",
"jest": "27.5.1",
"jest-environment-jsdom": "^27.5.1",
"lint-staged": "^10.2.11",
"lodash-es": "^4.17.21",
"moment-timezone": "^0.5.35",
"plop": "^2.7.4",
"postcss-loader": "^7.0.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-test-renderer": "^17.0.2",
"stylelint-config-prettier": "^9.0.3",
"stylelint-prettier": "^2.0.0",
"ts-jest": "^27.1.3",
"ts-jest": "29.0.3",
"ts-loader": "^9.3.1",
"typescript": "4.6.4",
"webpack-bundle-analyzer": "^4.6.1"

View file

@ -0,0 +1,31 @@
import React from 'react';
import { PENDING_COLOR, Tooltip, Icon } from '@grafana/ui';
import { Schedule } from 'models/schedule/schedule.types';
interface ScheduleWarningProps {
item: Schedule;
}
const ScheduleWarning = (props: ScheduleWarningProps) => {
const { item } = props;
if (item.warnings.length > 0) {
const tooltipContent = (
<div>
{item.warnings.map((warning: string, key: number) => (
<p key={key}>{warning}</p>
))}
</div>
);
return (
<Tooltip placement="top" content={tooltipContent}>
<Icon style={{ color: PENDING_COLOR }} name="exclamation-triangle" />
</Tooltip>
);
}
return null;
};
export default ScheduleWarning;

View file

@ -68,9 +68,8 @@ const SchedulesFilters = (props: SchedulesFiltersProps) => {
</Field>
<Field label="Type">
<RadioButtonGroup
disabled
options={[
{ label: 'All', value: 'all' },
{ label: 'All', value: undefined },
{
label: 'Web',
value: ScheduleType.API,
@ -84,7 +83,7 @@ const SchedulesFilters = (props: SchedulesFiltersProps) => {
value: ScheduleType.Calendar,
},
]}
value={value.type}
value={value?.type}
onChange={handleTypeChange}
/>
</Field>

View file

@ -28,7 +28,7 @@ import {
export class ScheduleStore extends BaseStore {
@observable
searchResult: { [key: string]: Array<Schedule['id']> } = {};
searchResult: { results?: Array<Schedule['id']> } = {};
@observable.shallow
items: { [id: string]: Schedule } = {};
@ -118,8 +118,11 @@ export class ScheduleStore extends BaseStore {
}
@action
async updateItems(query = '') {
const result = await makeRequest(this.path, { method: 'GET', params: { search: query } });
async updateItems(f: any = { searchTerm: '', type: undefined }) {
// async updateItems(query = '') {
const filters = typeof f === 'string' ? { searchTerm: f } : f;
const { searchTerm: search, type } = filters;
const result = await makeRequest(this.path, { method: 'GET', params: { search: search, type } });
this.items = {
...this.items,
@ -131,10 +134,9 @@ export class ScheduleStore extends BaseStore {
{}
),
};
this.searchResult = {
...this.searchResult,
[query]: result.map((item: Schedule) => item.id),
results: result.map((item: Schedule) => item.id),
};
}
@ -149,12 +151,11 @@ export class ScheduleStore extends BaseStore {
}
}
getSearchResult(query = '') {
if (!this.searchResult[query]) {
getSearchResult() {
if (!this.searchResult.results) {
return undefined;
}
return this.searchResult[query].map((scheduleId: Schedule['id']) => this.items[scheduleId]);
return this.searchResult?.results?.map((scheduleId: Schedule['id']) => this.items[scheduleId]);
}
@action

View file

@ -7,8 +7,7 @@ import '@testing-library/jest-dom';
import outgoingWebhooksStub from 'jest/outgoingWebhooksStub';
import { OutgoingWebhook } from 'models/outgoing_webhook/outgoing_webhook.types';
import { OutgoingWebhooks } from './OutgoingWebhooks';
import { OutgoingWebhooks } from 'pages/outgoing_webhooks/OutgoingWebhooks';
const outgoingWebhooks = outgoingWebhooksStub as OutgoingWebhook[];
const outgoingWebhookStore = () => ({
@ -21,12 +20,21 @@ const outgoingWebhookStore = () => ({
}, {}),
});
jest.mock('@grafana/runtime', () => ({
config: {
featureToggles: {
topNav: false,
},
},
}));
jest.mock('state/useStore', () => ({
useStore: () => ({
outgoingWebhookStore: outgoingWebhookStore(),
isUserActionAllowed: jest.fn().mockReturnValue(true),
}),
}));
jest.mock('@grafana/runtime', () => ({
getLocationSrv: jest.fn(),
}));

View file

@ -2,12 +2,14 @@ import React from 'react';
import { AppRootProps } from '@grafana/data';
import { getLocationSrv } from '@grafana/runtime';
import { Button, HorizontalGroup, VerticalGroup, IconButton, ToolbarButton, Icon } from '@grafana/ui';
import { Button, HorizontalGroup, VerticalGroup, IconButton, ToolbarButton, Icon, Modal } from '@grafana/ui';
import cn from 'classnames/bind';
import dayjs from 'dayjs';
import { omit } from 'lodash-es';
import { observer } from 'mobx-react';
import PluginLink from 'components/PluginLink/PluginLink';
import ScheduleWarning from 'components/ScheduleWarning/ScheduleWarning';
import Text from 'components/Text/Text';
import UserTimezoneSelect from 'components/UserTimezoneSelect/UserTimezoneSelect';
import WithConfirm from 'components/WithConfirm/WithConfirm';
@ -15,8 +17,9 @@ import Rotations from 'containers/Rotations/Rotations';
import ScheduleFinal from 'containers/Rotations/ScheduleFinal';
import ScheduleOverrides from 'containers/Rotations/ScheduleOverrides';
import ScheduleForm from 'containers/ScheduleForm/ScheduleForm';
import ScheduleICalSettings from 'containers/ScheduleIcalLink/ScheduleIcalLink';
import UsersTimezones from 'containers/UsersTimezones/UsersTimezones';
import { ScheduleType, Shift } from 'models/schedule/schedule.types';
import { Schedule, ScheduleType, Shift } from 'models/schedule/schedule.types';
import { Timezone } from 'models/timezone/timezone.types';
import { WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore';
@ -24,7 +27,6 @@ import { withMobXProviderContext } from 'state/withStore';
import { getStartOfWeek } from './Schedule.helpers';
import styles from './Schedule.module.css';
const cx = cn.bind(styles);
interface SchedulePageProps extends AppRootProps, WithStoreProps {}
@ -37,6 +39,7 @@ interface SchedulePageState {
shiftIdToShowOverridesForm?: Shift['id'];
isLoading: boolean;
showEditForm: boolean;
showScheduleICalSettings: boolean;
}
@observer
@ -53,6 +56,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
shiftIdToShowOverridesForm: undefined,
isLoading: true,
showEditForm: false,
showScheduleICalSettings: false,
};
}
@ -89,6 +93,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
shiftIdToShowRotationForm,
shiftIdToShowOverridesForm,
showEditForm,
showScheduleICalSettings,
} = this.state;
const { scheduleStore, currentTimezone } = store;
@ -111,6 +116,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
<Text.Title editable editModalTitle="Schedule name" level={2} onTextChange={this.handleNameChange}>
{schedule?.name}
</Text.Title>
{schedule && <ScheduleWarning item={schedule} />}
</HorizontalGroup>
<HorizontalGroup spacing="lg">
{users && (
@ -120,6 +126,16 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
</HorizontalGroup>
)}
<HorizontalGroup>
{schedule?.type === ScheduleType.Ical && (
<HorizontalGroup>
<Button variant="secondary" onClick={this.handleExportClick()}>
Export
</Button>
<Button variant="secondary" onClick={this.handleReloadClick(scheduleId)}>
Reload
</Button>
</HorizontalGroup>
)}
<ToolbarButton
icon="cog"
tooltip="Settings"
@ -214,6 +230,16 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
}}
/>
)}
{showScheduleICalSettings && (
<Modal
isOpen
title="Schedule export"
closeOnEscape
onDismiss={() => this.setState({ showScheduleICalSettings: false })}
>
<ScheduleICalSettings id={scheduleId} />
</Modal>
)}
</>
);
}
@ -367,6 +393,47 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
this.setState({ startMoment: startMoment.add(7, 'day') }, this.handleDateRangeUpdate);
};
handleExportClick = () => {
return () => {
this.setState({ showScheduleICalSettings: true });
};
};
handleReloadClick = (scheduleId: Schedule['id']) => {
const { store } = this.props;
const { scheduleStore } = store;
return async () => {
await scheduleStore.reloadIcal(scheduleId);
scheduleStore.updateItem(scheduleId);
this.updateEventsFor(scheduleId);
};
};
updateEventsFor = async (scheduleId: Schedule['id'], withEmpty = true, with_gap = true) => {
const {
store,
query: { id },
} = this.props;
const { scheduleStore } = store;
store.scheduleStore.scheduleToScheduleEvents = omit(store.scheduleStore.scheduleToScheduleEvents, [scheduleId]);
await scheduleStore.updateScheduleEvents(
scheduleId,
withEmpty,
with_gap,
dayjs().format('YYYY-MM-DD').toString(),
dayjs.tz.guess()
);
await store.scheduleStore.updateOncallShifts(id);
await this.updateEvents();
};
handleDelete = () => {
const {
store,

View file

@ -11,6 +11,7 @@ import Avatar from 'components/Avatar/Avatar';
import NewScheduleSelector from 'components/NewScheduleSelector/NewScheduleSelector';
import PluginLink from 'components/PluginLink/PluginLink';
import ScheduleCounter from 'components/ScheduleCounter/ScheduleCounter';
import ScheduleWarning from 'components/ScheduleWarning/ScheduleWarning';
import SchedulesFilters from 'components/SchedulesFilters_NEW/SchedulesFilters';
import { SchedulesFiltersType } from 'components/SchedulesFilters_NEW/SchedulesFilters.types';
import Table from 'components/Table/Table';
@ -51,7 +52,7 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
const { store } = this.props;
this.state = {
startMoment: getStartOfWeek(store.currentTimezone),
filters: { searchTerm: '', status: 'all', type: ScheduleType.API },
filters: { searchTerm: '', status: 'all', type: undefined },
showNewScheduleSelector: false,
expandedRowKeys: [],
scheduleIdToEdit: undefined,
@ -80,10 +81,10 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
render: this.renderType,
},
{
width: '10%',
width: '5%',
title: 'Status',
key: 'name',
render: this.renderStatus,
render: (item: Schedule) => this.renderStatus(item),
},
{
width: '30%',
@ -107,6 +108,11 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
title: 'Slack user group',
render: this.renderUserGroup,
},
{
width: '5%',
key: 'warning',
render: this.renderWarning,
},
{
width: '50px',
key: 'buttons',
@ -119,7 +125,6 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
const data = schedules
? schedules
.filter((schedule) => schedule.type === ScheduleType.API)
.filter(
(schedule) =>
filters.status === 'all' ||
@ -265,38 +270,52 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
return typeToVerbal[value];
};
renderWarning = (item: Schedule) => {
return <ScheduleWarning item={item} />;
};
renderStatus = (item: Schedule) => {
const {
store: { scheduleStore },
} = this.props;
const relatedEscalationChains = scheduleStore.relatedEscalationChains[item.id];
return (
<HorizontalGroup>
<ScheduleCounter
type="link"
count={item.number_of_escalation_chains}
tooltipTitle="Used in escalations"
tooltipContent={
<VerticalGroup spacing="sm">
{relatedEscalationChains ? (
relatedEscalationChains.length ? (
relatedEscalationChains.map((escalationChain) => (
<PluginLink key={escalationChain.pk} query={{ page: 'escalations', id: escalationChain.pk }}>
{escalationChain.name}
</PluginLink>
))
{item.number_of_escalation_chains > 0 && (
<ScheduleCounter
type="link"
count={item.number_of_escalation_chains}
tooltipTitle="Used in escalations"
tooltipContent={
<VerticalGroup spacing="sm">
{relatedEscalationChains ? (
relatedEscalationChains.length ? (
relatedEscalationChains.map((escalationChain) => (
<div key={escalationChain.pk}>
<PluginLink query={{ page: 'escalations', id: escalationChain.pk }}>
{escalationChain.name}
</PluginLink>
</div>
))
) : (
'Not used yet'
)
) : (
'Not used yet'
)
) : (
<LoadingPlaceholder>Loading related escalation chains....</LoadingPlaceholder>
)}
</VerticalGroup>
}
onHover={this.getUpdateRelatedEscalationChainsHandler(item.id)}
/>
<LoadingPlaceholder>Loading related escalation chains....</LoadingPlaceholder>
)}
</VerticalGroup>
}
onHover={this.getUpdateRelatedEscalationChainsHandler(item.id)}
/>
)}
{/* <ScheduleCounter
type="warning"
count={warningsCount}
tooltipTitle="Warnings"
tooltipContent="Schedule has unassigned time periods during next 7 days"
/>*/}
</HorizontalGroup>
);
};
@ -372,9 +391,10 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
};
applyFilters = () => {
// const { filters } = this.state;
// const { scheduleStore } = this.props.store;
// scheduleStore.updateItems(filters.searchTerm);
const { filters } = this.state;
const { store } = this.props;
const { scheduleStore } = store;
scheduleStore.updateItems(filters);
};
debouncedUpdateSchedules = debounce(this.applyFilters, 1000);

File diff suppressed because it is too large Load diff

View file

@ -8,13 +8,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.8
version: 1.0.9
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "v1.0.49"
appVersion: "v1.0.50"
dependencies:
- name: cert-manager
version: v1.8.0

View file

@ -237,15 +237,15 @@
{{- define "snippet.rabbitmq.env" -}}
{{- if eq .Values.broker.type "rabbitmq" -}}
{{- if and (not .Values.rabbitmq.enabled) (not .Values.externalRabbitmq.existingSecret) (not .Values.externalRabbitmq.usernameKey) .Values.externalRabbitmq.user }}
- name: RABBITMQ_USERNAME
value: {{ include "snippet.rabbitmq.user" . }}
{{- else if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.existingSecret .Values.externalRabbitmq.usernameKey (not .Values.externalRabbitmq.user) }}
{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.existingSecret .Values.externalRabbitmq.usernameKey (not .Values.externalRabbitmq.user) }}
- name: RABBITMQ_USERNAME
valueFrom:
secretKeyRef:
name: {{ include "snippet.rabbitmq.password.secret.name" . }}
key: {{ .Values.externalRabbitmq.usernameKey }}
{{- else }}
- name: RABBITMQ_USERNAME
value: {{ include "snippet.rabbitmq.user" . }}
{{- end }}
- name: RABBITMQ_PASSWORD
valueFrom: