Alert group column/label selector (#3281)
# What this PR does Adds new functionality to enable which columns should show on the alert group page  --------- Co-authored-by: Julia <ferril.darkdiver@gmail.com>
This commit is contained in:
parent
ec1f120d9c
commit
455f74560c
67 changed files with 2695 additions and 1013 deletions
|
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Add options to customize table columns in AlertGroup page ([3281](https://github.com/grafana/oncall/pull/3281))
|
||||
|
||||
### Fixed
|
||||
|
||||
- User profile UI tweaks ([#3443](https://github.com/grafana/oncall/pull/3443))
|
||||
|
|
|
|||
31
engine/apps/api/alert_group_table_columns.py
Normal file
31
engine/apps/api/alert_group_table_columns.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import typing
|
||||
|
||||
from apps.user_management.constants import AlertGroupTableColumns, default_columns
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from apps.user_management.models import User
|
||||
|
||||
|
||||
def alert_group_table_user_settings(user: "User") -> AlertGroupTableColumns:
|
||||
"""
|
||||
Returns user settings for alert group table columns. The flag "default" shows that user has default settings for
|
||||
visible columns. It's used by frontend to enable/disable `reset` button.
|
||||
This function uses lazy update to update columns settings for organization and for user.
|
||||
"""
|
||||
default_organization_columns = default_columns()
|
||||
if not user.organization.alert_group_table_columns:
|
||||
user.organization.update_alert_group_table_columns(default_organization_columns)
|
||||
organization_columns = user.organization.alert_group_table_columns
|
||||
if user.alert_group_table_selected_columns:
|
||||
visible_columns = [
|
||||
column for column in user.alert_group_table_selected_columns if column in organization_columns
|
||||
]
|
||||
else:
|
||||
visible_columns = default_organization_columns
|
||||
user.update_alert_group_table_selected_columns(visible_columns)
|
||||
hidden_columns = [column for column in organization_columns if column not in visible_columns]
|
||||
return {
|
||||
"visible": visible_columns,
|
||||
"hidden": hidden_columns,
|
||||
"default": visible_columns == default_organization_columns,
|
||||
}
|
||||
60
engine/apps/api/serializers/alert_group_table_settings.py
Normal file
60
engine/apps/api/serializers/alert_group_table_settings.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from apps.user_management.constants import (
|
||||
AlertGroupTableColumnTypeChoices,
|
||||
AlertGroupTableDefaultColumnChoices,
|
||||
default_columns,
|
||||
)
|
||||
|
||||
|
||||
class AlertGroupTableColumnSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(max_length=200)
|
||||
id = serializers.CharField(max_length=200)
|
||||
type = serializers.ChoiceField(choices=AlertGroupTableColumnTypeChoices.choices)
|
||||
|
||||
def validate(self, data):
|
||||
self._validate_id(data)
|
||||
return data
|
||||
|
||||
def _validate_id(self, data):
|
||||
"""Validate if `id` of column with `default` type is in the list of available default columns"""
|
||||
if (
|
||||
data["type"] == AlertGroupTableColumnTypeChoices.DEFAULT.value
|
||||
and data["id"] not in AlertGroupTableDefaultColumnChoices.values
|
||||
):
|
||||
raise ValidationError("Invalid column id format")
|
||||
|
||||
|
||||
class AlertGroupTableColumnsOrganizationSerializer(serializers.Serializer):
|
||||
visible = AlertGroupTableColumnSerializer(many=True)
|
||||
hidden = AlertGroupTableColumnSerializer(many=True)
|
||||
|
||||
def validate(self, data):
|
||||
"""
|
||||
Validate that at least one column is selected as visible and that all default columns are in the list.
|
||||
"""
|
||||
columns = data["visible"] + data["hidden"]
|
||||
request_columns_ids = [column["id"] for column in columns]
|
||||
if len(data["visible"]) == 0:
|
||||
raise ValidationError("At least one column should be selected as visible")
|
||||
elif not set(request_columns_ids) >= set(AlertGroupTableDefaultColumnChoices.values):
|
||||
raise ValidationError("Default column cannot be removed")
|
||||
elif len(request_columns_ids) > len(set(request_columns_ids)):
|
||||
raise ValidationError("Duplicate column")
|
||||
return data
|
||||
|
||||
|
||||
class AlertGroupTableColumnsUserSerializer(AlertGroupTableColumnsOrganizationSerializer):
|
||||
def validate(self, data):
|
||||
"""
|
||||
Validate that all columns exist in organization alert group table columns list.
|
||||
"""
|
||||
data = super().validate(data)
|
||||
columns = data["visible"] + data["hidden"]
|
||||
request_columns_ids = [column["id"] for column in columns]
|
||||
organization_columns = self.context["request"].auth.organization.alert_group_table_columns or default_columns()
|
||||
organization_columns_ids = [column["id"] for column in organization_columns]
|
||||
if set(organization_columns_ids) != set(request_columns_ids):
|
||||
raise ValidationError("Invalid settings")
|
||||
return data
|
||||
339
engine/apps/api/tests/test_alert_group_table_settings.py
Normal file
339
engine/apps/api/tests/test_alert_group_table_settings.py
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
import pytest
|
||||
from django.urls import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from apps.api.alert_group_table_columns import alert_group_table_user_settings
|
||||
from apps.api.permissions import LegacyAccessControlRole
|
||||
from apps.user_management.constants import AlertGroupTableColumnTypeChoices, default_columns
|
||||
|
||||
DEFAULT_COLUMNS = default_columns()
|
||||
|
||||
|
||||
def columns_settings(add_column=None):
|
||||
default_settings = {"visible": DEFAULT_COLUMNS[:], "hidden": [], "default": True}
|
||||
if add_column:
|
||||
default_settings["hidden"].append(add_column)
|
||||
return default_settings
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_columns(
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
organization, user, token = make_organization_and_user_with_plugin_token()
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-columns_settings")
|
||||
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
||||
expected_result = alert_group_table_user_settings(user)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == expected_result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"initial_columns_settings,updated_columns_settings,status_code",
|
||||
[
|
||||
# add column
|
||||
(
|
||||
columns_settings(),
|
||||
columns_settings({"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}),
|
||||
status.HTTP_200_OK,
|
||||
),
|
||||
# remove column
|
||||
(
|
||||
columns_settings({"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}),
|
||||
columns_settings(),
|
||||
status.HTTP_200_OK,
|
||||
),
|
||||
# wrong data format
|
||||
(columns_settings(), {}, status.HTTP_400_BAD_REQUEST),
|
||||
(columns_settings(), {"visible": []}, status.HTTP_400_BAD_REQUEST),
|
||||
(columns_settings(), {"hidden": []}, status.HTTP_400_BAD_REQUEST),
|
||||
# wrong id
|
||||
(
|
||||
columns_settings(),
|
||||
columns_settings({"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.DEFAULT.value}),
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
),
|
||||
# duplicate id
|
||||
(
|
||||
columns_settings(),
|
||||
columns_settings({"name": "Test", "id": 1, "type": AlertGroupTableColumnTypeChoices.DEFAULT.value}),
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
),
|
||||
# remove default column
|
||||
(
|
||||
columns_settings(),
|
||||
{"visible": DEFAULT_COLUMNS[:-1], "hidden": []},
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_update_columns_list(
|
||||
initial_columns_settings,
|
||||
updated_columns_settings,
|
||||
status_code,
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
"""Test alert group table settings for organization (POST request)"""
|
||||
organization, user, token = make_organization_and_user_with_plugin_token()
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-columns_settings")
|
||||
client.post(url, data=initial_columns_settings, format="json", **make_user_auth_headers(user, token))
|
||||
response = client.post(url, data=updated_columns_settings, format="json", **make_user_auth_headers(user, token))
|
||||
assert response.status_code == status_code
|
||||
if status_code == status.HTTP_200_OK:
|
||||
assert response.json() == updated_columns_settings
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"initial_columns_settings,updated_columns_settings,status_code",
|
||||
[
|
||||
# hide column
|
||||
(columns_settings(), {"visible": DEFAULT_COLUMNS[:-1], "hidden": DEFAULT_COLUMNS[-1:]}, status.HTTP_200_OK),
|
||||
# make column visible
|
||||
({"visible": DEFAULT_COLUMNS[:-1], "hidden": DEFAULT_COLUMNS[-1:]}, columns_settings(), status.HTTP_200_OK),
|
||||
# wrong data format
|
||||
(columns_settings(), {}, status.HTTP_400_BAD_REQUEST),
|
||||
(columns_settings(), {"visible": []}, status.HTTP_400_BAD_REQUEST),
|
||||
(columns_settings(), {"hidden": []}, status.HTTP_400_BAD_REQUEST),
|
||||
# hide all columns
|
||||
(columns_settings(), {"visible": [], "hidden": DEFAULT_COLUMNS[:]}, status.HTTP_400_BAD_REQUEST),
|
||||
# add column
|
||||
(
|
||||
columns_settings(),
|
||||
columns_settings({"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}),
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
),
|
||||
# remove column
|
||||
(
|
||||
columns_settings({"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}),
|
||||
columns_settings(),
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_update_columns_settings(
|
||||
initial_columns_settings,
|
||||
updated_columns_settings,
|
||||
status_code,
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
"""Test alert group table settings for user (PUT request)"""
|
||||
organization, user, token = make_organization_and_user_with_plugin_token()
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-columns_settings")
|
||||
client.post(url, data=initial_columns_settings, format="json", **make_user_auth_headers(user, token))
|
||||
response = client.put(url, data=updated_columns_settings, format="json", **make_user_auth_headers(user, token))
|
||||
assert response.status_code == status_code
|
||||
if status_code == status.HTTP_200_OK:
|
||||
updated_columns_settings["default"] = updated_columns_settings["visible"] == DEFAULT_COLUMNS
|
||||
assert response.json() == updated_columns_settings
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_reset_user_columns(
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
"""Test reset alert group table settings for user"""
|
||||
organization, user, token = make_organization_and_user_with_plugin_token()
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-reset_columns_settings")
|
||||
new_column = {"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}
|
||||
organization.update_alert_group_table_columns(default_columns() + [new_column])
|
||||
user.update_alert_group_table_selected_columns(organization.alert_group_table_columns[1::-1])
|
||||
default_settings = columns_settings(new_column)
|
||||
assert alert_group_table_user_settings(user) != default_settings
|
||||
response = client.post(url, format="json", **make_user_auth_headers(user, token))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == default_settings
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"role,expected_status",
|
||||
[
|
||||
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.EDITOR, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.VIEWER, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
|
||||
],
|
||||
)
|
||||
def test_get_columns_permissions(
|
||||
role,
|
||||
expected_status,
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
organization, user, token = make_organization_and_user_with_plugin_token(role)
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-columns_settings")
|
||||
response = client.get(url, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == expected_status
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"role,expected_status",
|
||||
[
|
||||
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.EDITOR, status.HTTP_403_FORBIDDEN),
|
||||
(LegacyAccessControlRole.VIEWER, status.HTTP_403_FORBIDDEN),
|
||||
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
|
||||
],
|
||||
)
|
||||
def test_update_columns_list_permissions(
|
||||
role,
|
||||
expected_status,
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
organization, user, token = make_organization_and_user_with_plugin_token(role)
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-columns_settings")
|
||||
data = columns_settings()
|
||||
response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == expected_status
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"role,expected_status",
|
||||
[
|
||||
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.EDITOR, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.VIEWER, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
|
||||
],
|
||||
)
|
||||
def test_update_columns_settings_permissions(
|
||||
role,
|
||||
expected_status,
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
organization, user, token = make_organization_and_user_with_plugin_token(role)
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-columns_settings")
|
||||
data = columns_settings()
|
||||
response = client.put(url, data=data, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == expected_status
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"role,expected_status",
|
||||
[
|
||||
(LegacyAccessControlRole.ADMIN, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.EDITOR, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.VIEWER, status.HTTP_200_OK),
|
||||
(LegacyAccessControlRole.NONE, status.HTTP_403_FORBIDDEN),
|
||||
],
|
||||
)
|
||||
def test_reset_user_columns_permissions(
|
||||
role,
|
||||
expected_status,
|
||||
make_organization_and_user_with_plugin_token,
|
||||
make_user_auth_headers,
|
||||
):
|
||||
organization, user, token = make_organization_and_user_with_plugin_token(role)
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alert_group_table-reset_columns_settings")
|
||||
response = client.post(url, format="json", **make_user_auth_headers(user, token))
|
||||
|
||||
assert response.status_code == expected_status
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"user_settings,organization_settings,expected_result",
|
||||
[
|
||||
# user doesn't have settings, organization has default settings - all columns are visible
|
||||
(
|
||||
None,
|
||||
DEFAULT_COLUMNS,
|
||||
{"visible": DEFAULT_COLUMNS, "hidden": [], "default": True},
|
||||
),
|
||||
# user doesn't have settings, organization has updated settings - only default columns are visible
|
||||
(
|
||||
None,
|
||||
DEFAULT_COLUMNS + [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}],
|
||||
{
|
||||
"visible": DEFAULT_COLUMNS,
|
||||
"hidden": [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}],
|
||||
"default": True,
|
||||
},
|
||||
),
|
||||
# user has settings, organization has default settings - only selected columns are visible
|
||||
(
|
||||
DEFAULT_COLUMNS[:3],
|
||||
DEFAULT_COLUMNS,
|
||||
{"visible": DEFAULT_COLUMNS[:3], "hidden": DEFAULT_COLUMNS[3:], "default": False},
|
||||
),
|
||||
# user has settings, organization has unchanged settings - only selected columns are visible
|
||||
(
|
||||
DEFAULT_COLUMNS[:3]
|
||||
+ [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}],
|
||||
DEFAULT_COLUMNS + [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}],
|
||||
{
|
||||
"visible": (
|
||||
DEFAULT_COLUMNS[:3]
|
||||
+ [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}]
|
||||
),
|
||||
"hidden": DEFAULT_COLUMNS[3:],
|
||||
"default": False,
|
||||
},
|
||||
),
|
||||
# user has settings, organization has updated settings - column was removed, remove from settings
|
||||
(
|
||||
DEFAULT_COLUMNS[:3]
|
||||
+ [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}],
|
||||
DEFAULT_COLUMNS,
|
||||
{"visible": DEFAULT_COLUMNS[:3], "hidden": DEFAULT_COLUMNS[3:], "default": False},
|
||||
),
|
||||
# user has settings with reordered columns, organization has unchanged settings - selected columns in particular
|
||||
# order are visible
|
||||
(
|
||||
[
|
||||
DEFAULT_COLUMNS[1],
|
||||
DEFAULT_COLUMNS[3],
|
||||
{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value},
|
||||
DEFAULT_COLUMNS[2],
|
||||
],
|
||||
DEFAULT_COLUMNS + [{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value}],
|
||||
{
|
||||
"visible": [
|
||||
DEFAULT_COLUMNS[1],
|
||||
DEFAULT_COLUMNS[3],
|
||||
{"name": "Test", "id": "test", "type": AlertGroupTableColumnTypeChoices.LABEL.value},
|
||||
DEFAULT_COLUMNS[2],
|
||||
],
|
||||
"hidden": DEFAULT_COLUMNS[:1] + DEFAULT_COLUMNS[4:],
|
||||
"default": False,
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_alert_group_table_user_settings(
|
||||
user_settings,
|
||||
organization_settings,
|
||||
expected_result,
|
||||
make_organization_and_user,
|
||||
):
|
||||
organization, user = make_organization_and_user()
|
||||
organization.update_alert_group_table_columns(organization_settings)
|
||||
if user_settings:
|
||||
user.update_alert_group_table_selected_columns(user_settings)
|
||||
result = alert_group_table_user_settings(user)
|
||||
assert result == expected_result
|
||||
assert user.alert_group_table_selected_columns == result["visible"]
|
||||
|
|
@ -4,6 +4,7 @@ from common.api_helpers.optional_slash_router import OptionalSlashRouter, option
|
|||
|
||||
from .views import UserNotificationPolicyView, auth
|
||||
from .views.alert_group import AlertGroupView
|
||||
from .views.alert_group_table_settings import AlertGroupTableColumnsViewSet
|
||||
from .views.alert_receive_channel import AlertReceiveChannelView
|
||||
from .views.alert_receive_channel_template import AlertReceiveChannelTemplateView
|
||||
from .views.alerts import AlertDetailView
|
||||
|
|
@ -143,3 +144,19 @@ urlpatterns += [
|
|||
name="alert_group_labels-get_key",
|
||||
),
|
||||
]
|
||||
|
||||
# Alert group table settings
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r"^alertgroup_table_settings/?$",
|
||||
AlertGroupTableColumnsViewSet.as_view(
|
||||
{"get": "get_columns", "put": "update_user_columns", "post": "update_organization_columns"}
|
||||
),
|
||||
name="alert_group_table-columns_settings",
|
||||
),
|
||||
re_path(
|
||||
r"^alertgroup_table_settings/reset?$",
|
||||
AlertGroupTableColumnsViewSet.as_view({"post": "reset_user_columns"}),
|
||||
name="alert_group_table-reset_columns_settings",
|
||||
),
|
||||
]
|
||||
|
|
|
|||
55
engine/apps/api/views/alert_group_table_settings.py
Normal file
55
engine/apps/api/views/alert_group_table_settings.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import typing
|
||||
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
||||
from apps.api.alert_group_table_columns import alert_group_table_user_settings
|
||||
from apps.api.permissions import RBACPermission
|
||||
from apps.api.serializers.alert_group_table_settings import (
|
||||
AlertGroupTableColumnsOrganizationSerializer,
|
||||
AlertGroupTableColumnsUserSerializer,
|
||||
)
|
||||
from apps.api.views.labels import LabelsFeatureFlagViewSet
|
||||
from apps.auth_token.auth import PluginAuthentication
|
||||
from apps.user_management.constants import AlertGroupTableColumn, default_columns
|
||||
|
||||
|
||||
class AlertGroupTableColumnsViewSet(LabelsFeatureFlagViewSet):
|
||||
authentication_classes = (PluginAuthentication,)
|
||||
permission_classes = (IsAuthenticated, RBACPermission)
|
||||
|
||||
rbac_permissions = {
|
||||
"get_columns": [RBACPermission.Permissions.ALERT_GROUPS_READ],
|
||||
"update_user_columns": [RBACPermission.Permissions.ALERT_GROUPS_READ],
|
||||
"reset_user_columns": [RBACPermission.Permissions.ALERT_GROUPS_READ],
|
||||
"update_organization_columns": [RBACPermission.Permissions.OTHER_SETTINGS_WRITE],
|
||||
}
|
||||
|
||||
def get_columns(self, request: Request) -> Response:
|
||||
return Response(alert_group_table_user_settings(request.user))
|
||||
|
||||
def update_organization_columns(self, request: Request) -> Response:
|
||||
"""add/remove columns for organization"""
|
||||
serializer = AlertGroupTableColumnsOrganizationSerializer(data=request.data, context={"request": request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
columns: typing.List[AlertGroupTableColumn] = serializer.validated_data.get(
|
||||
"visible", []
|
||||
) + serializer.validated_data.get("hidden", [])
|
||||
request.auth.organization.update_alert_group_table_columns(columns)
|
||||
return Response(alert_group_table_user_settings(request.user))
|
||||
|
||||
def update_user_columns(self, request: Request) -> Response:
|
||||
"""select/hide/change order for user"""
|
||||
user = request.user
|
||||
serializer = AlertGroupTableColumnsUserSerializer(data=request.data, context={"request": request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
columns: typing.List[AlertGroupTableColumn] = serializer.validated_data.get("visible", [])
|
||||
user.update_alert_group_table_selected_columns(columns)
|
||||
return Response(alert_group_table_user_settings(user))
|
||||
|
||||
def reset_user_columns(self, request: Request) -> Response:
|
||||
"""set default alert group table settings for user"""
|
||||
user = request.user
|
||||
user.update_alert_group_table_selected_columns(default_columns())
|
||||
return Response(alert_group_table_user_settings(user))
|
||||
39
engine/apps/user_management/constants.py
Normal file
39
engine/apps/user_management/constants.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import typing
|
||||
|
||||
from django.db.models import TextChoices
|
||||
|
||||
|
||||
class AlertGroupTableDefaultColumnChoices(TextChoices):
|
||||
STATUS = "status", "Status"
|
||||
ID = "id", "ID"
|
||||
TITLE = "title", "Title"
|
||||
ALERTS = "alerts", "Alerts"
|
||||
INTEGRATION = "integration", "Integration"
|
||||
CREATED = "created", "Created"
|
||||
LABELS = "labels", "Labels"
|
||||
TEAM = "team", "Team"
|
||||
USERS = "users", "Users"
|
||||
|
||||
|
||||
class AlertGroupTableColumnTypeChoices(TextChoices):
|
||||
DEFAULT = "default"
|
||||
LABEL = "label"
|
||||
|
||||
|
||||
class AlertGroupTableColumn(typing.TypedDict):
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
|
||||
|
||||
class AlertGroupTableColumns(typing.TypedDict):
|
||||
visible: typing.List[AlertGroupTableColumn]
|
||||
hidden: typing.List[AlertGroupTableColumn]
|
||||
default: bool
|
||||
|
||||
|
||||
def default_columns() -> typing.List[AlertGroupTableColumn]:
|
||||
return [
|
||||
{"name": column.label, "id": column.value, "type": AlertGroupTableColumnTypeChoices.DEFAULT.value}
|
||||
for column in AlertGroupTableDefaultColumnChoices
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.20 on 2023-11-15 12:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('user_management', '0017_alter_organization_maintenance_author'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='alert_group_table_columns',
|
||||
field=models.JSONField(default=None, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='alert_group_table_selected_columns',
|
||||
field=models.JSONField(default=None, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -6,11 +6,12 @@ from urllib.parse import urljoin
|
|||
from django.conf import settings
|
||||
from django.core.validators import MinLengthValidator
|
||||
from django.db import models
|
||||
from django.db.models import Count, Q
|
||||
from django.db.models import Count, JSONField, Q
|
||||
from django.utils import timezone
|
||||
from mirage import fields as mirage_fields
|
||||
|
||||
from apps.alerts.models import MaintainableObject
|
||||
from apps.user_management.constants import AlertGroupTableColumn
|
||||
from apps.user_management.subscription_strategy import FreePublicBetaSubscriptionStrategy
|
||||
from common.insight_log import ChatOpsEvent, ChatOpsTypePlug, write_chatops_insight_log
|
||||
from common.oncall_gateway import create_oncall_connector, delete_oncall_connector, delete_slack_connector
|
||||
|
|
@ -248,6 +249,8 @@ class Organization(MaintainableObject):
|
|||
is_rbac_permissions_enabled = models.BooleanField(default=False)
|
||||
is_grafana_incident_enabled = models.BooleanField(default=False)
|
||||
|
||||
alert_group_table_columns: list[AlertGroupTableColumn] | None = JSONField(default=None, null=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ("stack_id", "org_id")
|
||||
|
||||
|
|
@ -283,6 +286,11 @@ class Organization(MaintainableObject):
|
|||
def emails_left(self, user):
|
||||
return self.subscription_strategy.emails_left(user)
|
||||
|
||||
def update_alert_group_table_columns(self, columns: typing.List[AlertGroupTableColumn]) -> None:
|
||||
if columns != self.alert_group_table_columns:
|
||||
self.alert_group_table_columns = columns
|
||||
self.save(update_fields=["alert_group_table_columns"])
|
||||
|
||||
def set_general_log_channel(self, channel_id, channel_name, user):
|
||||
if self.general_log_channel_id != channel_id:
|
||||
old_general_log_channel_id = self.slack_team_identity.cached_channels.filter(
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ from apps.api.permissions import (
|
|||
user_is_authorized,
|
||||
)
|
||||
from apps.schedules.tasks import drop_cached_ical_for_custom_events_for_organization
|
||||
from apps.user_management.constants import AlertGroupTableColumn
|
||||
from common.public_primary_keys import generate_public_primary_key, increase_public_primary_key_length
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
|
|
@ -236,6 +237,8 @@ class User(models.Model):
|
|||
is_active = models.BooleanField(null=True, default=True)
|
||||
permissions = models.JSONField(null=False, default=list)
|
||||
|
||||
alert_group_table_selected_columns: list[AlertGroupTableColumn] | None = models.JSONField(default=None, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.pk}: {self.username}"
|
||||
|
||||
|
|
@ -449,6 +452,11 @@ class User(models.Model):
|
|||
),
|
||||
)
|
||||
|
||||
def update_alert_group_table_selected_columns(self, columns: typing.List[AlertGroupTableColumn]) -> None:
|
||||
if self.alert_group_table_selected_columns != columns:
|
||||
self.alert_group_table_selected_columns = columns
|
||||
self.save(update_fields=["alert_group_table_selected_columns"])
|
||||
|
||||
|
||||
# TODO: check whether this signal can be moved to save method of the model
|
||||
@receiver(post_save, sender=User)
|
||||
|
|
|
|||
|
|
@ -55,20 +55,17 @@ export const filterAlertGroupsTableByIntegrationAndGoToDetailPage = async (
|
|||
await selectElement.type(integrationName);
|
||||
await selectValuePickerValue(page, integrationName, false);
|
||||
|
||||
/**
|
||||
* wait for the alert groups to be filtered then by this particular integration (toBeVisible assertion),
|
||||
* then click on the alert group and go to the individual alert group page
|
||||
*/
|
||||
const firstTableRow = page.locator('table > tbody > tr:first-child');
|
||||
|
||||
try {
|
||||
/**
|
||||
* wait for up to 5 seconds for the alert groups to be filtered, if the first row does not correspond
|
||||
* wait for up to 2 seconds for the alert groups to be filtered, if the first row does not correspond
|
||||
* to `integrationName` assume that the background workers have not created it yet and lets
|
||||
* recursively retry this function
|
||||
*/
|
||||
await firstTableRow.getByText(integrationName).waitFor({ state: 'visible', timeout: 5000 });
|
||||
await firstTableRow.locator('td:nth-child(4) a').click();
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
expect(await page.locator('table > tbody > tr [data-testid=integration-name]').textContent()).toBe(integrationName);
|
||||
await page.locator('table > tbody > tr [data-testid=integration-url]').click();
|
||||
} catch (err) {
|
||||
return filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName, (retryNum += 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,3 +19,34 @@ Object.defineProperty(window, 'matchMedia', {
|
|||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
Object.defineProperty(window, 'ResizeObserver', {
|
||||
writable: true,
|
||||
value: class ResizeObserver {
|
||||
constructor(callback: ResizeObserverCallback) {
|
||||
setTimeout(() => {
|
||||
callback(
|
||||
[
|
||||
{
|
||||
contentRect: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
width: 500,
|
||||
height: 500,
|
||||
top: 100,
|
||||
bottom: 0,
|
||||
left: 100,
|
||||
right: 0,
|
||||
},
|
||||
target: {},
|
||||
} as ResizeObserverEntry,
|
||||
],
|
||||
this
|
||||
);
|
||||
});
|
||||
}
|
||||
observe() {}
|
||||
disconnect() {}
|
||||
unobserve() {}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-responsive": "^8.0.5",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-test-renderer": "^17.0.2",
|
||||
"@types/react-test-renderer": "^18.0.5",
|
||||
"@types/react-transition-group": "^4.4.5",
|
||||
"@types/throttle-debounce": "^5.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.1",
|
||||
|
|
@ -101,9 +101,9 @@
|
|||
"openapi-typescript": "^7.0.0-next.4",
|
||||
"plop": "^2.7.4",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-test-renderer": "^18.0.2",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-prettier": "^2.0.0",
|
||||
"ts-jest": "29.0.3",
|
||||
|
|
@ -116,18 +116,22 @@
|
|||
"node": ">=14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@dnd-kit/utilities": "^3.2.1",
|
||||
"@grafana/data": "^9.2.4",
|
||||
"@grafana/faro-web-sdk": "^1.0.0-beta4",
|
||||
"@grafana/faro-web-tracing": "^1.0.0-beta4",
|
||||
"@grafana/labels": "1.3.4",
|
||||
"@grafana/labels": "~1.3.5",
|
||||
"@grafana/runtime": "9.3.0-beta1",
|
||||
"@grafana/ui": "^9.4.7",
|
||||
"@grafana/ui": "^10.2.0",
|
||||
"@opentelemetry/api": "^1.3.0",
|
||||
"array-move": "^4.0.0",
|
||||
"change-case": "^4.1.1",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"dayjs": "^1.11.5",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"immutability-helper": "^3.1.1",
|
||||
"mobx": "5.13.0",
|
||||
"mobx-react": "6.1.1",
|
||||
"object-hash": "^3.0.0",
|
||||
|
|
|
|||
|
|
@ -44,9 +44,8 @@
|
|||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.rc-table-cell {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
td.rc-table-cell {
|
||||
height: 44px !important;
|
||||
|
||||
/* works better than break-all, especially for table headers */
|
||||
word-break: break-word;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,10 @@
|
|||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.overflow-child--line-1 {
|
||||
-webkit-line-clamp: 1;
|
||||
}
|
||||
|
||||
.break-word {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
|
@ -150,3 +154,40 @@
|
|||
.line-clamp-3 {
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
|
||||
/* -----
|
||||
* CSSTransitionGroup fading
|
||||
*/
|
||||
|
||||
.fade-enter {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fade-enter.fade-enter-active {
|
||||
max-height: 50px;
|
||||
opacity: 1;
|
||||
transition: opacity 300ms ease-in, max-height 300ms ease-in;
|
||||
}
|
||||
|
||||
.fade-leave {
|
||||
opacity: 1;
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
.fade-leave.fade-leave-active {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 300ms ease-in, max-height 300ms ease-in;
|
||||
}
|
||||
|
||||
.fade-exit {
|
||||
opacity: 1;
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
.fade-exit.fade-exit-active {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 300ms ease-in, max-height 300ms ease-in;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const CheatSheet = (props: CheatSheetProps) => {
|
|||
<VerticalGroup>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Text strong>{cheatSheetName} cheatsheet</Text>
|
||||
<IconButton name="times" onClick={onClose} />
|
||||
<IconButton aria-label="Close" name="times" onClick={onClose} />
|
||||
</HorizontalGroup>
|
||||
<Text type="secondary">{cheatSheetData.description}</Text>
|
||||
<div className={cx('u-width-100')}>
|
||||
|
|
@ -70,7 +70,7 @@ const CheatSheetListItem = (props: CheatSheetListItemProps) => {
|
|||
{item.codeExample}
|
||||
</Text>
|
||||
<CopyToClipboard text={item.codeExample} onCopy={() => openNotification('Example copied')}>
|
||||
<IconButton name="copy" />
|
||||
<IconButton aria-label="Copy" name="copy" />
|
||||
</CopyToClipboard>
|
||||
</HorizontalGroup>
|
||||
</Block>
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ const GTable = <RT extends DefaultRecordType = DefaultRecordType>(props: Props<R
|
|||
|
||||
if (rowSelection) {
|
||||
columns.unshift({
|
||||
width: '25px',
|
||||
width: '40px',
|
||||
key: 'check',
|
||||
title: (
|
||||
<Checkbox
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ const IntegrationCollapsibleTreeItem: React.FC<{
|
|||
<div className={cx('integrationTree__group', { 'integrationTree__group--hidden': item.isHidden })}>
|
||||
<div className={cx('integrationTree__icon')}>
|
||||
{item.canHoverIcon ? (
|
||||
<IconButton name={getIconName()} onClick={iconOnClickFn} size="lg" />
|
||||
<IconButton aria-label="" name={getIconName()} onClick={iconOnClickFn} size="lg" />
|
||||
) : (
|
||||
<Icon name={getIconName()} onClick={iconOnClickFn} size="lg" />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ const IntegrationContactPoint: React.FC<{
|
|||
return (
|
||||
<HorizontalGroup spacing="md">
|
||||
<IconButton
|
||||
aria-label="Alert Manager"
|
||||
name="external-link-alt"
|
||||
onClick={() => {
|
||||
window.open(
|
||||
|
|
@ -277,6 +278,7 @@ const IntegrationContactPoint: React.FC<{
|
|||
}
|
||||
>
|
||||
<IconButton
|
||||
aria-label="Disconnect Contact Point"
|
||||
name="trash-alt"
|
||||
onClick={() => {
|
||||
alertReceiveChannelStore
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ const IntegrationInputField: React.FC<IntegrationInputFieldProps> = ({
|
|||
|
||||
<div className={cx('icons')}>
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
{showEye && <IconButton name={'eye'} size={'xs'} onClick={onInputReveal} />}
|
||||
{showEye && <IconButton aria-label="Reveal" name={'eye'} size={'xs'} onClick={onInputReveal} />}
|
||||
{showCopy && (
|
||||
<CopyToClipboard text={value} onCopy={onCopy}>
|
||||
<IconButton name={'copy'} size={'xs'} />
|
||||
<IconButton aria-label="Copy" name={'copy'} size={'xs'} />
|
||||
</CopyToClipboard>
|
||||
)}
|
||||
{showExternal && <IconButton name={'external-link-alt'} size={'xs'} onClick={onOpen} />}
|
||||
{showExternal && <IconButton aria-label="Open" name={'external-link-alt'} size={'xs'} onClick={onOpen} />}
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ export class NotificationPolicy extends React.Component<NotificationPolicyProps,
|
|||
{this._renderControls(isDisabled)}
|
||||
<WithPermissionControlTooltip userAction={userAction}>
|
||||
<IconButton
|
||||
aria-label="Remove"
|
||||
className={cx('control')}
|
||||
name="trash-alt"
|
||||
onClick={this._getDeleteClickHandler(id)}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,11 @@ export const ScheduleQualityDetails: FC<ScheduleQualityDetailsProps> = ({ qualit
|
|||
Calculation methodology
|
||||
</Text>
|
||||
</HorizontalGroup>
|
||||
<IconButton name={expanded ? 'arrow-down' : 'arrow-right'} onClick={handleExpandClick} />
|
||||
<IconButton
|
||||
aria-label={expanded ? 'Collapse' : 'Expand'}
|
||||
name={expanded ? 'arrow-down' : 'arrow-right'}
|
||||
onClick={handleExpandClick}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
{expanded && (
|
||||
<Text type="primary" className={cx('text')}>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,13 @@ const SourceCode: FC<SourceCodeProps> = (props) => {
|
|||
>
|
||||
{showClipboardIconOnly ? (
|
||||
<Tooltip placement="top" content="Copy to Clipboard">
|
||||
<IconButton className={cx('copyIcon')} size={'lg'} name="copy" data-testid="test__copyIcon" />
|
||||
<IconButton
|
||||
aria-label="Copy"
|
||||
className={cx('copyIcon')}
|
||||
size={'lg'}
|
||||
name="copy"
|
||||
data-testid="test__copyIcon"
|
||||
/>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ exports[`Unauthorized renders properly - access control enabled: false 1`] = `
|
|||
className="not-found"
|
||||
>
|
||||
<div
|
||||
className="css-9ztktj-vertical-group"
|
||||
className="css-8tu8mo-vertical-group"
|
||||
style={
|
||||
Object {
|
||||
"height": "100%",
|
||||
|
|
@ -14,7 +14,7 @@ exports[`Unauthorized renders properly - access control enabled: false 1`] = `
|
|||
}
|
||||
>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h1
|
||||
className="title error-code"
|
||||
|
|
@ -32,7 +32,7 @@ exports[`Unauthorized renders properly - access control enabled: false 1`] = `
|
|||
</h1>
|
||||
</div>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
className="title"
|
||||
|
|
@ -63,7 +63,7 @@ exports[`Unauthorized renders properly - access control enabled: true 1`] = `
|
|||
className="not-found"
|
||||
>
|
||||
<div
|
||||
className="css-9ztktj-vertical-group"
|
||||
className="css-8tu8mo-vertical-group"
|
||||
style={
|
||||
Object {
|
||||
"height": "100%",
|
||||
|
|
@ -72,7 +72,7 @@ exports[`Unauthorized renders properly - access control enabled: true 1`] = `
|
|||
}
|
||||
>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h1
|
||||
className="title error-code"
|
||||
|
|
@ -90,7 +90,7 @@ exports[`Unauthorized renders properly - access control enabled: true 1`] = `
|
|||
</h1>
|
||||
</div>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
className="title"
|
||||
|
|
@ -121,7 +121,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Admin 1
|
|||
className="not-found"
|
||||
>
|
||||
<div
|
||||
className="css-9ztktj-vertical-group"
|
||||
className="css-8tu8mo-vertical-group"
|
||||
style={
|
||||
Object {
|
||||
"height": "100%",
|
||||
|
|
@ -130,7 +130,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Admin 1
|
|||
}
|
||||
>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h1
|
||||
className="title error-code"
|
||||
|
|
@ -148,7 +148,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Admin 1
|
|||
</h1>
|
||||
</div>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
className="title"
|
||||
|
|
@ -179,7 +179,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Editor
|
|||
className="not-found"
|
||||
>
|
||||
<div
|
||||
className="css-9ztktj-vertical-group"
|
||||
className="css-8tu8mo-vertical-group"
|
||||
style={
|
||||
Object {
|
||||
"height": "100%",
|
||||
|
|
@ -188,7 +188,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Editor
|
|||
}
|
||||
>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h1
|
||||
className="title error-code"
|
||||
|
|
@ -206,7 +206,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Editor
|
|||
</h1>
|
||||
</div>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
className="title"
|
||||
|
|
@ -237,7 +237,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Viewer
|
|||
className="not-found"
|
||||
>
|
||||
<div
|
||||
className="css-9ztktj-vertical-group"
|
||||
className="css-8tu8mo-vertical-group"
|
||||
style={
|
||||
Object {
|
||||
"height": "100%",
|
||||
|
|
@ -246,7 +246,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Viewer
|
|||
}
|
||||
>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h1
|
||||
className="title error-code"
|
||||
|
|
@ -264,7 +264,7 @@ exports[`Unauthorized renders properly the grammar for different roles - Viewer
|
|||
</h1>
|
||||
</div>
|
||||
<div
|
||||
className="css-1ec9088-layoutChildrenWrapper"
|
||||
className="css-qxdyop-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
className="title"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ interface UserGroupsProps {
|
|||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
const DragHandle = () => <IconButton className={cx('icon')} name="draggabledots" />;
|
||||
const DragHandle = () => <IconButton aria-label="Drag" className={cx('icon')} name="draggabledots" />;
|
||||
|
||||
const SortableHandleHoc = SortableHandle(DragHandle);
|
||||
|
||||
|
|
@ -101,7 +101,12 @@ const UserGroups = (props: UserGroupsProps) => {
|
|||
{!disabled && (
|
||||
<div className={cx('user-buttons')}>
|
||||
<HorizontalGroup>
|
||||
<IconButton className={cx('icon')} name="trash-alt" onClick={getDeleteItemHandler(index)} />
|
||||
<IconButton
|
||||
aria-label="Remove"
|
||||
className={cx('icon')}
|
||||
name="trash-alt"
|
||||
onClick={getDeleteItemHandler(index)}
|
||||
/>
|
||||
<SortableHandleHoc />
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import { ContextMenu } from '@grafana/ui';
|
|||
export interface WithContextMenuProps {
|
||||
children: (props: { openMenu: React.MouseEventHandler<HTMLElement> }) => JSX.Element;
|
||||
renderMenuItems: ({ closeMenu }: { closeMenu?: () => void }) => React.ReactNode;
|
||||
isOpen?: boolean;
|
||||
|
||||
forceIsOpen?: boolean;
|
||||
focusOnOpen?: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ exports[`AddResponders should properly display the add responders button when hi
|
|||
class="root root_bordered"
|
||||
>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
class="title"
|
||||
|
|
@ -26,30 +26,18 @@ exports[`AddResponders should properly display the add responders button when hi
|
|||
</h4>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="css-b2ba3d-button"
|
||||
class="css-8b29hm-button"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-1gebccs"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19,11H13V5a1,1,0,0,0-2,0v6H5a1,1,0,0,0,0,2h6v6a1,1,0,0,0,2,0V13h6a1,1,0,0,0,0-2Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Invite
|
||||
</span>
|
||||
|
|
@ -74,11 +62,11 @@ exports[`AddResponders should properly display the add responders button when hi
|
|||
class="root root_bordered"
|
||||
>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
class="title"
|
||||
|
|
@ -108,11 +96,11 @@ exports[`AddResponders should render properly in create mode 1`] = `
|
|||
class="root root_bordered"
|
||||
>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
class="title"
|
||||
|
|
@ -125,30 +113,18 @@ exports[`AddResponders should render properly in create mode 1`] = `
|
|||
</h4>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="css-b2ba3d-button"
|
||||
class="css-8b29hm-button"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-1gebccs"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19,11H13V5a1,1,0,0,0-2,0v6H5a1,1,0,0,0,0,2h6v6a1,1,0,0,0,2,0V13h6a1,1,0,0,0,0-2Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Invite
|
||||
</span>
|
||||
|
|
@ -173,11 +149,11 @@ exports[`AddResponders should render properly in update mode 1`] = `
|
|||
class="root root_bordered"
|
||||
>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
class="title"
|
||||
|
|
@ -190,30 +166,18 @@ exports[`AddResponders should render properly in update mode 1`] = `
|
|||
</h4>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="css-b2ba3d-button"
|
||||
class="css-8b29hm-button"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-1gebccs"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19,11H13V5a1,1,0,0,0-2,0v6H5a1,1,0,0,0,0,2h6v6a1,1,0,0,0,2,0V13h6a1,1,0,0,0,0-2Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Add
|
||||
</span>
|
||||
|
|
@ -238,11 +202,11 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="root root_bordered"
|
||||
>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<h4
|
||||
class="title"
|
||||
|
|
@ -255,30 +219,18 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</h4>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="css-b2ba3d-button"
|
||||
class="css-8b29hm-button"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-1gebccs"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19,11H13V5a1,1,0,0,0-2,0v6H5a1,1,0,0,0,0,2h6v6a1,1,0,0,0,2,0V13h6a1,1,0,0,0,0-2Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Invite
|
||||
</span>
|
||||
|
|
@ -291,18 +243,18 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
>
|
||||
<li>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="timeline-icon-background"
|
||||
|
|
@ -315,7 +267,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--undefined text--medium responder-name"
|
||||
|
|
@ -326,47 +278,36 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
aria-label="Remove responder"
|
||||
class="css-x1vujn"
|
||||
class="css-17584xm"
|
||||
data-testid="team-responder-delete-icon"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-hj6vlq"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18ZM20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Zm-3-1a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="timeline-icon-background timeline-icon-background--green"
|
||||
|
|
@ -379,7 +320,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--undefined text--medium responder-name"
|
||||
|
|
@ -390,17 +331,17 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-19xfdrs-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
class="css-e49k3t-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
|
|
@ -413,16 +354,16 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="css-1scgfe8"
|
||||
class="css-1i88p6p"
|
||||
>
|
||||
<div
|
||||
class="css-1kl463j-grafana-select-value-container"
|
||||
class="css-1q0c0d5-grafana-select-value-container"
|
||||
>
|
||||
<div
|
||||
class=" css-1yc0yww-placeholder"
|
||||
class=" css-1n8tjau-placeholder"
|
||||
id="react-select-2-placeholder"
|
||||
>
|
||||
Choose
|
||||
Select...
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
|
|
@ -440,51 +381,28 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
class="css-uvldi-input-suffix"
|
||||
class="css-zyjsuv-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17,9.17a1,1,0,0,0-1.41,0L12,12.71,8.46,9.17a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42l4.24,4.24a1,1,0,0,0,1.42,0L17,10.59A1,1,0,0,0,17,9.17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
aria-label="Remove responder"
|
||||
class="css-x1vujn"
|
||||
class="css-17584xm"
|
||||
data-testid="user-responder-delete-icon"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-hj6vlq"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18ZM20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Zm-3-1a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -493,18 +411,18 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</li>
|
||||
<li>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="timeline-icon-background timeline-icon-background--green"
|
||||
|
|
@ -517,7 +435,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--undefined text--medium responder-name"
|
||||
|
|
@ -528,17 +446,17 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-15fuo2f-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
class="css-1nmqu8c-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
|
|
@ -551,16 +469,16 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="css-1scgfe8"
|
||||
class="css-1i88p6p"
|
||||
>
|
||||
<div
|
||||
class="css-1kl463j-grafana-select-value-container"
|
||||
class="css-1q0c0d5-grafana-select-value-container"
|
||||
>
|
||||
<div
|
||||
class=" css-1yc0yww-placeholder"
|
||||
class=" css-1n8tjau-placeholder"
|
||||
id="react-select-3-placeholder"
|
||||
>
|
||||
Choose
|
||||
Select...
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
|
|
@ -577,51 +495,28 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
class="css-uvldi-input-suffix"
|
||||
class="css-zyjsuv-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17,9.17a1,1,0,0,0-1.41,0L12,12.71,8.46,9.17a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42l4.24,4.24a1,1,0,0,0,1.42,0L17,10.59A1,1,0,0,0,17,9.17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
aria-label="Remove responder"
|
||||
class="css-x1vujn"
|
||||
class="css-17584xm"
|
||||
data-testid="user-responder-delete-icon"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-hj6vlq"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18ZM20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Zm-3-1a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -630,18 +525,18 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</li>
|
||||
<li>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="timeline-icon-background timeline-icon-background--green"
|
||||
|
|
@ -654,7 +549,7 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--undefined text--medium responder-name"
|
||||
|
|
@ -665,17 +560,17 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-15fuo2f-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
class="css-1nmqu8c-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
|
|
@ -688,16 +583,16 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="css-1scgfe8"
|
||||
class="css-1i88p6p"
|
||||
>
|
||||
<div
|
||||
class="css-1kl463j-grafana-select-value-container"
|
||||
class="css-1q0c0d5-grafana-select-value-container"
|
||||
>
|
||||
<div
|
||||
class=" css-1yc0yww-placeholder"
|
||||
class=" css-1n8tjau-placeholder"
|
||||
id="react-select-4-placeholder"
|
||||
>
|
||||
Choose
|
||||
Select...
|
||||
</div>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
|
|
@ -714,51 +609,28 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
class="css-uvldi-input-suffix"
|
||||
class="css-zyjsuv-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17,9.17a1,1,0,0,0-1.41,0L12,12.71,8.46,9.17a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42l4.24,4.24a1,1,0,0,0,1.42,0L17,10.59A1,1,0,0,0,17,9.17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
aria-label="Remove responder"
|
||||
class="css-x1vujn"
|
||||
class="css-17584xm"
|
||||
data-testid="user-responder-delete-icon"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-hj6vlq"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18ZM20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Zm-3-1a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -767,81 +639,63 @@ exports[`AddResponders should render selected team and users properly 1`] = `
|
|||
</li>
|
||||
<div
|
||||
aria-label="[object Object]"
|
||||
class="css-j2xd7x"
|
||||
class="css-10yjoiw"
|
||||
data-testid="data-testid Alert info"
|
||||
role="status"
|
||||
>
|
||||
<div
|
||||
class="css-38nxtd"
|
||||
class="css-1td7znu"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
class="css-ufgc62"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
data-name="Layer 1"
|
||||
height="24"
|
||||
id="Layer_1"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
<div
|
||||
class="css-tluiue"
|
||||
>
|
||||
<path
|
||||
d="M12,2A10,10,0,1,0,22,12,10.01114,10.01114,0,0,0,12,2Zm0,18a8,8,0,1,1,8-8A8.00917,8.00917,0,0,1,12,20Zm0-8.5a1,1,0,0,0-1,1v3a1,1,0,0,0,2,0v-3A1,1,0,0,0,12,11.5Zm0-4a1.25,1.25,0,1,0,1.25,1.25A1.25,1.25,0,0,0,12,7.5Z"
|
||||
<div
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-zmuccj"
|
||||
>
|
||||
<div
|
||||
class="css-hui7p1"
|
||||
class="css-1gmwkrf"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
class="css-9om60p"
|
||||
>
|
||||
<a
|
||||
class="learn-more-link"
|
||||
href="https://grafana.com/docs/oncall/latest/notify/#configure-user-notification-policies"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
>
|
||||
<span
|
||||
class="root text text--link text--medium"
|
||||
<a
|
||||
class="learn-more-link"
|
||||
href="https://grafana.com/docs/oncall/latest/notify/#configure-user-notification-policies"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
<span
|
||||
class="root text text--link text--medium"
|
||||
>
|
||||
<div
|
||||
class="css-12pko5d-layoutChildrenWrapper"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
<div
|
||||
class="css-12pko5d-layoutChildrenWrapper"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
class="css-12kn7ff-layoutChildrenWrapper"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18,10.82a1,1,0,0,0-1,1V19a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V8A1,1,0,0,1,5,7h7.18a1,1,0,0,0,0-2H5A3,3,0,0,0,2,8V19a3,3,0,0,0,3,3H16a3,3,0,0,0,3-3V11.82A1,1,0,0,0,18,10.82Zm3.92-8.2a1,1,0,0,0-.54-.54A1,1,0,0,0,21,2H15a1,1,0,0,0,0,2h3.59L8.29,14.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L20,5.41V9a1,1,0,0,0,2,0V3A1,1,0,0,0,21.92,2.62Z"
|
||||
/>
|
||||
</svg>
|
||||
Learn more
|
||||
</div>
|
||||
<div
|
||||
class="css-12kn7ff-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</a>
|
||||
about Default vs Important user personal notification settings
|
||||
</span>
|
||||
</a>
|
||||
about Default vs Important user personal notification settings
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,81 +7,79 @@ exports[`AddRespondersPopup it shows a loading message initially 1`] = `
|
|||
data-testid="add-responders-popup"
|
||||
>
|
||||
<div
|
||||
class="css-11uftlx-input-wrapper responders-filters"
|
||||
class="css-qfli5h-input-wrapper responders-filters"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1w5c5dq-input-inputWrapper"
|
||||
class="css-10lnb82-input-inputWrapper"
|
||||
>
|
||||
<input
|
||||
class="css-1mlczho-input-input"
|
||||
class="css-8tk2dk-input-input"
|
||||
data-testid="add-responders-search-input"
|
||||
placeholder="Search"
|
||||
style="padding-right: 12px;"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
class="css-7y3u6k-input-suffix"
|
||||
class="css-7099m8-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M21.71,20.29,18,16.61A9,9,0,1,0,16.61,18l3.68,3.68a1,1,0,0,0,1.42,0A1,1,0,0,0,21.71,20.29ZM11,18a7,7,0,1,1,7-7A7,7,0,0,1,11,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="radio-buttons css-sv3u8u"
|
||||
class="radio-buttons css-1nxrz2e"
|
||||
role="radiogroup"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="css-8hl977"
|
||||
id="option-teams-radiogroup-1"
|
||||
name="radiogroup-1"
|
||||
type="radio"
|
||||
/>
|
||||
<label
|
||||
class="css-1tpfx0m"
|
||||
for="option-teams-radiogroup-1"
|
||||
<div
|
||||
class="css-1hvl7lx"
|
||||
>
|
||||
Teams
|
||||
|
||||
</label>
|
||||
<input
|
||||
class="css-8hl977"
|
||||
id="option-users-radiogroup-1"
|
||||
name="radiogroup-1"
|
||||
type="radio"
|
||||
/>
|
||||
<label
|
||||
class="css-1tpfx0m"
|
||||
for="option-users-radiogroup-1"
|
||||
<input
|
||||
checked=""
|
||||
class="css-1f9hgw3"
|
||||
id="option-teams-radiogroup-1"
|
||||
name="radiogroup-1"
|
||||
type="radio"
|
||||
/>
|
||||
<label
|
||||
class="css-10bka4u"
|
||||
for="option-teams-radiogroup-1"
|
||||
>
|
||||
Teams
|
||||
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="css-1hvl7lx"
|
||||
>
|
||||
Users
|
||||
|
||||
</label>
|
||||
<input
|
||||
class="css-1f9hgw3"
|
||||
id="option-users-radiogroup-1"
|
||||
name="radiogroup-1"
|
||||
type="radio"
|
||||
/>
|
||||
<label
|
||||
class="css-10bka4u"
|
||||
for="option-users-radiogroup-1"
|
||||
>
|
||||
Users
|
||||
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-lq6a48 loading-placeholder"
|
||||
class="css-1yjvs5a loading-placeholder"
|
||||
>
|
||||
Loading...
|
||||
|
||||
<div
|
||||
class="css-13pg8vy"
|
||||
class="css-1tqtz24"
|
||||
data-testid="Spinner"
|
||||
>
|
||||
<i
|
||||
aria-label="loading spinner"
|
||||
class="fa fa-spinner fa-spin fa-spin"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
exports[`NotificationPoliciesSelect disabled state 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-19xfdrs-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
class="css-e49k3t-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
|
|
@ -16,13 +16,13 @@ exports[`NotificationPoliciesSelect disabled state 1`] = `
|
|||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="css-1scgfe8"
|
||||
class="css-1i88p6p"
|
||||
>
|
||||
<div
|
||||
class="css-1kl463j-grafana-select-value-container"
|
||||
class="css-1q0c0d5-grafana-select-value-container"
|
||||
>
|
||||
<div
|
||||
class="css-3hgwt1-singleValue css-upz218-SingleValue"
|
||||
class="css-sr1xkh-singleValue css-upz218-SingleValue"
|
||||
>
|
||||
Default
|
||||
</div>
|
||||
|
|
@ -41,23 +41,11 @@ exports[`NotificationPoliciesSelect disabled state 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
class="css-uvldi-input-suffix"
|
||||
class="css-zyjsuv-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17,9.17a1,1,0,0,0-1.41,0L12,12.71,8.46,9.17a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42l4.24,4.24a1,1,0,0,0,1.42,0L17,10.59A1,1,0,0,0,17,9.17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -67,7 +55,7 @@ exports[`NotificationPoliciesSelect disabled state 1`] = `
|
|||
exports[`NotificationPoliciesSelect it renders properly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-15fuo2f-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
class="css-1nmqu8c-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
|
|
@ -80,13 +68,13 @@ exports[`NotificationPoliciesSelect it renders properly 1`] = `
|
|||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="css-1scgfe8"
|
||||
class="css-1i88p6p"
|
||||
>
|
||||
<div
|
||||
class="css-1kl463j-grafana-select-value-container"
|
||||
class="css-1q0c0d5-grafana-select-value-container"
|
||||
>
|
||||
<div
|
||||
class="css-144maed-singleValue css-upz218-SingleValue"
|
||||
class="css-8nwx1l-singleValue css-upz218-SingleValue"
|
||||
>
|
||||
Default
|
||||
</div>
|
||||
|
|
@ -104,23 +92,11 @@ exports[`NotificationPoliciesSelect it renders properly 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
class="css-uvldi-input-suffix"
|
||||
class="css-zyjsuv-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17,9.17a1,1,0,0,0-1.41,0L12,12.71,8.46,9.17a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42l4.24,4.24a1,1,0,0,0,1.42,0L17,10.59A1,1,0,0,0,17,9.17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ exports[`TeamResponder it renders data properly 1`] = `
|
|||
<div>
|
||||
<li>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="timeline-icon-background"
|
||||
|
|
@ -28,7 +28,7 @@ exports[`TeamResponder it renders data properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--undefined text--medium responder-name"
|
||||
|
|
@ -39,29 +39,18 @@ exports[`TeamResponder it renders data properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
aria-label="Remove responder"
|
||||
class="css-x1vujn"
|
||||
class="css-17584xm"
|
||||
data-testid="team-responder-delete-icon"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-hj6vlq"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18ZM20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Zm-3-1a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ exports[`UserResponder it renders data properly 1`] = `
|
|||
<div>
|
||||
<li>
|
||||
<div
|
||||
class="css-on8nbh-horizontal-group"
|
||||
class="css-1mhys9y-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="timeline-icon-background timeline-icon-background--green"
|
||||
|
|
@ -28,7 +28,7 @@ exports[`UserResponder it renders data properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--undefined text--medium responder-name"
|
||||
|
|
@ -39,17 +39,17 @@ exports[`UserResponder it renders data properly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-15fuo2f-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
class="css-1nmqu8c-input-wrapper select css-8k5qe3-SelectContainer"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
|
|
@ -62,13 +62,13 @@ exports[`UserResponder it renders data properly 1`] = `
|
|||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="css-1scgfe8"
|
||||
class="css-1i88p6p"
|
||||
>
|
||||
<div
|
||||
class="css-1kl463j-grafana-select-value-container"
|
||||
class="css-1q0c0d5-grafana-select-value-container"
|
||||
>
|
||||
<div
|
||||
class="css-144maed-singleValue css-upz218-SingleValue"
|
||||
class="css-8nwx1l-singleValue css-upz218-SingleValue"
|
||||
>
|
||||
Important
|
||||
</div>
|
||||
|
|
@ -86,51 +86,28 @@ exports[`UserResponder it renders data properly 1`] = `
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
class="css-uvldi-input-suffix"
|
||||
class="css-zyjsuv-input-suffix"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M17,9.17a1,1,0,0,0-1.41,0L12,12.71,8.46,9.17a1,1,0,0,0-1.41,0,1,1,0,0,0,0,1.42l4.24,4.24a1,1,0,0,0,1.42,0L17,10.59A1,1,0,0,0,17,9.17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
aria-label="Remove responder"
|
||||
class="css-x1vujn"
|
||||
class="css-17584xm"
|
||||
data-testid="user-responder-delete-icon"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-hj6vlq"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10,18a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,10,18ZM20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Zm-3-1a1,1,0,0,0,1-1V11a1,1,0,0,0-2,0v6A1,1,0,0,0,14,18Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
export const getColumnsSelectorStyles = (_theme: GrafanaTheme2) => {
|
||||
return {
|
||||
columnsSelectorView: css`
|
||||
min-width: 230px;
|
||||
`,
|
||||
|
||||
columnsVisibleSection: css`
|
||||
margin-bottom: 16px;
|
||||
`,
|
||||
|
||||
columnsHeader: css`
|
||||
display: block !important;
|
||||
margin-bottom: 16px;
|
||||
`,
|
||||
columnsHeaderSmall: css`
|
||||
display: block !important;
|
||||
margin-bottom: 8px;
|
||||
`,
|
||||
|
||||
columnsHeaderSecondary: css`
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
`,
|
||||
|
||||
columnsHiddenSection: css`
|
||||
margin-bottom: 20px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
`,
|
||||
columnsSelectorButtons: css`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
`,
|
||||
|
||||
columnItem: css`
|
||||
gap: 12px;
|
||||
display: flex;
|
||||
padding-left: 25px;
|
||||
|
||||
&:hover .columns-icon-trash {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
|
||||
columnsCheckbox: css`
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
`,
|
||||
|
||||
columnsIcon: css`
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
|
||||
&::before {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -60%);
|
||||
}
|
||||
`,
|
||||
|
||||
columnsIconTrash: css`
|
||||
display: none;
|
||||
`,
|
||||
|
||||
columnRow: css`
|
||||
position: relative;
|
||||
margin-bottom: 6px;
|
||||
height: 22px;
|
||||
`,
|
||||
|
||||
columnName: css`
|
||||
text-wrap: nowrap;
|
||||
max-width: 180px;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
`,
|
||||
|
||||
labelIcon: css`
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
import React, { useRef } from 'react';
|
||||
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
DragEndEvent,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
verticalListSortingStrategy,
|
||||
useSortable,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { Button, Checkbox, Icon, IconButton, LoadingPlaceholder, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||
|
||||
import RenderConditionally from 'components/RenderConditionally/RenderConditionally';
|
||||
import Text from 'components/Text/Text';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { AlertGroupColumn, AlertGroupColumnType } from 'models/alertgroup/alertgroup.types';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openErrorNotification } from 'utils';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
import { WrapAutoLoadingState } from 'utils/decorators';
|
||||
|
||||
import { getColumnsSelectorStyles } from './ColumnsSelector.styles';
|
||||
|
||||
const TRANSITION_MS = 500;
|
||||
|
||||
interface ColumnRowProps {
|
||||
column: AlertGroupColumn;
|
||||
onItemChange: (id: number | string) => void;
|
||||
onColumnRemoval: (column: AlertGroupColumn) => void;
|
||||
}
|
||||
|
||||
const ColumnRow: React.FC<ColumnRowProps> = ({ column, onItemChange, onColumnRemoval }) => {
|
||||
const dnd = useSortable({ id: column.id });
|
||||
|
||||
const styles = useStyles2(getColumnsSelectorStyles);
|
||||
|
||||
const { attributes, listeners, setNodeRef, transform, transition } = dnd;
|
||||
const columnElRef = useRef<HTMLDivElement>(undefined);
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={setNodeRef} style={{ ...style }} className={styles.columnRow}>
|
||||
<div className={styles.columnItem} ref={columnElRef}>
|
||||
<span className={styles.columnName}>{column.name}</span>
|
||||
|
||||
{column.type === AlertGroupColumnType.LABEL && (
|
||||
<Tooltip content="Label Column">
|
||||
<Icon aria-label="Label" name="tag-alt" className={styles.labelIcon} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<RenderConditionally shouldRender={column.isVisible}>
|
||||
<IconButton
|
||||
aria-label="Drag"
|
||||
name="draggabledots"
|
||||
className={styles.columnsIcon}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
/>
|
||||
</RenderConditionally>
|
||||
|
||||
<RenderConditionally shouldRender={!column.isVisible && column.type === AlertGroupColumnType.LABEL}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.OtherSettingsWrite}>
|
||||
<IconButton
|
||||
className={[styles.columnsIcon, styles.columnsIconTrash, 'columns-icon-trash'].join(' ')}
|
||||
name="trash-alt"
|
||||
aria-label="Remove"
|
||||
tooltip={'Remove column'}
|
||||
onClick={() => onColumnRemoval(column)}
|
||||
/>
|
||||
</WithPermissionControlTooltip>
|
||||
</RenderConditionally>
|
||||
</div>
|
||||
|
||||
<Checkbox
|
||||
className={styles.columnsCheckbox}
|
||||
type="checkbox"
|
||||
value={column.isVisible}
|
||||
onChange={() => onItemChange(column.id)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ColumnsSelectorProps {
|
||||
onColumnAddModalOpen(): void;
|
||||
onConfirmRemovalModalOpen(column: AlertGroupColumn): void;
|
||||
}
|
||||
|
||||
export const ColumnsSelector: React.FC<ColumnsSelectorProps> = observer(
|
||||
({ onColumnAddModalOpen, onConfirmRemovalModalOpen }) => {
|
||||
const { alertGroupStore, loaderStore } = useStore();
|
||||
|
||||
const styles = useStyles2(getColumnsSelectorStyles);
|
||||
|
||||
const { columns, isDefaultColumnOrder } = alertGroupStore;
|
||||
|
||||
const visibleColumns = columns.filter((col) => col.isVisible);
|
||||
const hiddenColumns = columns
|
||||
.filter((col) => !col.isVisible)
|
||||
.sort((a, b) => a.id.toString().localeCompare(b.id.toString()));
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
})
|
||||
);
|
||||
|
||||
const isResetLoading = loaderStore.isLoading(ActionKey.RESET_COLUMNS_FROM_ALERT_GROUP);
|
||||
|
||||
return (
|
||||
<div className={styles.columnsSelectorView}>
|
||||
<Text type="primary" className={styles.columnsHeader}>
|
||||
Columns Settings
|
||||
</Text>
|
||||
|
||||
<div className={styles.columnsVisibleSection}>
|
||||
<Text type="primary" className={styles.columnsHeaderSmall}>
|
||||
Visible ({visibleColumns.length})
|
||||
</Text>
|
||||
|
||||
<DndContext
|
||||
autoScroll={{ layoutShiftCompensation: false }}
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={(ev) => handleDragEnd(ev, true)}
|
||||
>
|
||||
<SortableContext items={columns} strategy={verticalListSortingStrategy}>
|
||||
<TransitionGroup>
|
||||
{visibleColumns.map((column) => (
|
||||
<CSSTransition key={column.id} timeout={TRANSITION_MS} unmountOnExit classNames="fade">
|
||||
<ColumnRow
|
||||
key={column.id}
|
||||
column={column}
|
||||
onItemChange={onItemChange}
|
||||
onColumnRemoval={onConfirmRemovalModalOpen}
|
||||
/>
|
||||
</CSSTransition>
|
||||
))}
|
||||
</TransitionGroup>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
|
||||
<div className={styles.columnsHiddenSection}>
|
||||
<Text type="primary" className={styles.columnsHeaderSmall}>
|
||||
Hidden ({hiddenColumns.length})
|
||||
</Text>
|
||||
|
||||
<DndContext
|
||||
autoScroll={{ layoutShiftCompensation: false }}
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={(ev) => handleDragEnd(ev, false)}
|
||||
>
|
||||
<SortableContext items={columns} strategy={verticalListSortingStrategy}>
|
||||
<TransitionGroup>
|
||||
{hiddenColumns.map((column) => (
|
||||
<CSSTransition key={column.id} timeout={TRANSITION_MS} classNames="fade">
|
||||
<ColumnRow
|
||||
key={column.id}
|
||||
column={column}
|
||||
onItemChange={onItemChange}
|
||||
onColumnRemoval={onConfirmRemovalModalOpen}
|
||||
/>
|
||||
</CSSTransition>
|
||||
))}
|
||||
</TransitionGroup>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
|
||||
<div className={styles.columnsSelectorButtons}>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
tooltipPlacement="top"
|
||||
tooltip={'Reset table to default columns'}
|
||||
disabled={isResetLoading || isDefaultColumnOrder}
|
||||
onClick={WrapAutoLoadingState(onReset, ActionKey.RESET_COLUMNS_FROM_ALERT_GROUP)}
|
||||
>
|
||||
{isResetLoading ? <LoadingPlaceholder text="Loading..." className="loadingPlaceholder" /> : 'Reset'}
|
||||
</Button>
|
||||
<WithPermissionControlTooltip userAction={UserActions.OtherSettingsWrite}>
|
||||
<Button variant={'primary'} disabled={isResetLoading} icon="plus" onClick={onColumnAddModalOpen}>
|
||||
Add
|
||||
</Button>
|
||||
</WithPermissionControlTooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
async function onReset() {
|
||||
await alertGroupStore.resetTableSettings();
|
||||
await alertGroupStore.fetchTableSettings();
|
||||
}
|
||||
|
||||
async function onItemChange(id: string | number) {
|
||||
const checkedItems = alertGroupStore.columns.filter((col) => col.isVisible);
|
||||
if (checkedItems.length === 1 && checkedItems[0].id === id) {
|
||||
openErrorNotification('At least one column should be selected');
|
||||
return;
|
||||
}
|
||||
|
||||
alertGroupStore.columns = alertGroupStore.columns.map((item): AlertGroupColumn => {
|
||||
let newItem: AlertGroupColumn = { ...item, isVisible: !item.isVisible };
|
||||
return item.id === id ? newItem : item;
|
||||
});
|
||||
|
||||
await alertGroupStore.updateTableSettings(convertColumnsToTableSettings(alertGroupStore.columns), true);
|
||||
}
|
||||
|
||||
function handleDragEnd(event: DragEndEvent, isVisible: boolean) {
|
||||
const { active, over } = event;
|
||||
|
||||
let searchableList: AlertGroupColumn[] = isVisible ? visibleColumns : hiddenColumns;
|
||||
|
||||
if (active.id !== over.id) {
|
||||
const oldIndex = searchableList.findIndex((item) => item.id === active.id);
|
||||
const newIndex = searchableList.findIndex((item) => item.id === over.id);
|
||||
|
||||
searchableList = arrayMove(searchableList, oldIndex, newIndex);
|
||||
|
||||
const updatedList = isVisible ? [...searchableList, ...hiddenColumns] : [...visibleColumns, ...searchableList];
|
||||
alertGroupStore.columns = updatedList;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export function convertColumnsToTableSettings(columns: AlertGroupColumn[]): {
|
||||
visible: AlertGroupColumn[];
|
||||
hidden: AlertGroupColumn[];
|
||||
} {
|
||||
const tableSettings: { visible: AlertGroupColumn[]; hidden: AlertGroupColumn[] } = {
|
||||
visible: columns.filter((col: AlertGroupColumn) => col.isVisible),
|
||||
hidden: columns.filter((col: AlertGroupColumn) => !col.isVisible),
|
||||
};
|
||||
|
||||
return tableSettings;
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import { LabelTag } from '@grafana/labels';
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
HorizontalGroup,
|
||||
IconButton,
|
||||
Input,
|
||||
LoadingPlaceholder,
|
||||
Modal,
|
||||
VerticalGroup,
|
||||
useStyles2,
|
||||
} from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import Block from 'components/GBlock/Block';
|
||||
import Text from 'components/Text/Text';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { AlertGroupColumn, AlertGroupColumnType } from 'models/alertgroup/alertgroup.types';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { components } from 'network/oncall-api/autogenerated-api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openErrorNotification, pluralize } from 'utils';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
import { useDebouncedCallback } from 'utils/hooks';
|
||||
|
||||
import { getColumnsSelectorWrapperStyles } from './ColumnsSelectorWrapper.styles';
|
||||
|
||||
interface ColumnsModalProps {
|
||||
isModalOpen: boolean;
|
||||
labelKeys: Array<ApiSchemas['LabelKey']>;
|
||||
setIsModalOpen: (value: boolean) => void;
|
||||
inputRef: React.RefObject<HTMLInputElement>;
|
||||
}
|
||||
|
||||
interface SearchResult extends Pick<components['schemas']['LabelKey'], 'id' | 'name'> {
|
||||
isChecked: boolean;
|
||||
isCollapsed: boolean;
|
||||
values: any[];
|
||||
}
|
||||
|
||||
const DEBOUNCE_MS = 300;
|
||||
|
||||
export const ColumnsModal: React.FC<ColumnsModalProps> = observer(
|
||||
({ isModalOpen, labelKeys, setIsModalOpen, inputRef }) => {
|
||||
const store = useStore();
|
||||
const styles = useStyles2(getColumnsSelectorWrapperStyles);
|
||||
|
||||
const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
|
||||
const debouncedOnInputChange = useDebouncedCallback(onInputChange, DEBOUNCE_MS);
|
||||
|
||||
const isLoading = store.loaderStore.isLoading(ActionKey.ADD_NEW_COLUMN_TO_ALERT_GROUP);
|
||||
|
||||
const availableKeysForSearching = useMemo(() => {
|
||||
const currentAGColumns = store.alertGroupStore.columns.map((col) => col.name);
|
||||
return labelKeys.filter((pair) => currentAGColumns.indexOf(pair.name) === -1);
|
||||
}, [labelKeys, store.alertGroupStore.columns]);
|
||||
|
||||
return (
|
||||
<Modal isOpen={isModalOpen} title={'Add column'} onDismiss={onCloseModal} closeOnEscape={false}>
|
||||
<VerticalGroup spacing="md">
|
||||
<div className={styles.content}>
|
||||
<VerticalGroup spacing="md">
|
||||
<Input
|
||||
className={styles.input}
|
||||
autoFocus
|
||||
placeholder="Search..."
|
||||
ref={inputRef}
|
||||
onChange={debouncedOnInputChange}
|
||||
/>
|
||||
|
||||
{inputRef?.current?.value === '' && (
|
||||
<Text type="primary">
|
||||
{availableKeysForSearching.length} {pluralize('item', availableKeysForSearching.length)} available.
|
||||
Type to see suggestions
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{inputRef?.current?.value && searchResults.length && (
|
||||
<VerticalGroup spacing="xs">
|
||||
{searchResults.map((result, index) => (
|
||||
<VerticalGroup key={index}>
|
||||
<div className={styles.fieldRow}>
|
||||
<IconButton
|
||||
aria-label={result.isCollapsed ? 'Expand' : 'Collapse'}
|
||||
name={result.isCollapsed ? 'angle-right' : 'angle-down'}
|
||||
onClick={() => expandOrCollapseSearchResultItem(result, index)}
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
type="checkbox"
|
||||
className={styles.checkboxAddOption}
|
||||
value={result.isChecked}
|
||||
onChange={() => {
|
||||
setSearchResults((items) => {
|
||||
return items.map((item) => {
|
||||
const updatedItem: SearchResult = { ...item, isChecked: !item.isChecked };
|
||||
return item.id === result.id ? updatedItem : item;
|
||||
});
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text type="primary">{result.name}</Text>
|
||||
</div>
|
||||
{!result.isCollapsed && (
|
||||
<Block bordered withBackground fullWidth className={styles.valuesBlock}>
|
||||
{result.values === undefined ? (
|
||||
<LoadingPlaceholder text="Loading..." className="loadingPlaceholder" />
|
||||
) : (
|
||||
renderLabelValues(result.name, result.values)
|
||||
)}
|
||||
</Block>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
))}
|
||||
</VerticalGroup>
|
||||
)}
|
||||
|
||||
{inputRef?.current?.value && searchResults.length === 0 && (
|
||||
<Text type="primary">0 results for your search.</Text>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
|
||||
<HorizontalGroup justify="flex-end" spacing="md">
|
||||
<Button variant="secondary" onClick={onCloseModal}>
|
||||
Close
|
||||
</Button>
|
||||
<WithPermissionControlTooltip userAction={UserActions.OtherSettingsWrite}>
|
||||
<Button
|
||||
disabled={isLoading || !searchResults.find((it) => it.isChecked)}
|
||||
variant="primary"
|
||||
onClick={onAddNewColumns}
|
||||
>
|
||||
{isLoading ? <LoadingPlaceholder className={'loader'} text="Loading..." /> : 'Add'}
|
||||
</Button>
|
||||
</WithPermissionControlTooltip>
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
function renderLabelValues(keyName: string, values: Array<ApiSchemas['LabelValue']>) {
|
||||
return (
|
||||
<HorizontalGroup spacing="xs">
|
||||
{values.slice(0, 2).map((val) => (
|
||||
<LabelTag label={keyName} value={val.name} key={val.id} />
|
||||
))}
|
||||
<div className={styles.totalValuesCount}>{values.length > 2 ? `+ ${values.length - 2}` : ``}</div>
|
||||
</HorizontalGroup>
|
||||
);
|
||||
}
|
||||
|
||||
async function expandOrCollapseSearchResultItem(result: SearchResult, index: number) {
|
||||
setSearchResults((items) =>
|
||||
items.map((it, idx) => (idx === index ? { ...it, isCollapsed: !it.isCollapsed } : it))
|
||||
);
|
||||
|
||||
await fetchLabelValues(result, index);
|
||||
}
|
||||
|
||||
async function fetchLabelValues(result: SearchResult, index: number) {
|
||||
const labelResponse = await store.alertGroupStore.loadValuesForLabelKey(result.id);
|
||||
|
||||
setSearchResults((items) =>
|
||||
items.map((it, idx) => (idx === index ? { ...it, values: labelResponse.values } : it))
|
||||
);
|
||||
}
|
||||
|
||||
function onCloseModal() {
|
||||
inputRef.current.value = '';
|
||||
|
||||
setSearchResults([]);
|
||||
setIsModalOpen(false);
|
||||
setTimeout(forceOpenToggletip, 0);
|
||||
}
|
||||
|
||||
async function onAddNewColumns() {
|
||||
const mergedColumns = [
|
||||
...store.alertGroupStore.columns,
|
||||
...searchResults
|
||||
.filter((item) => item.isChecked)
|
||||
.map(
|
||||
(item): AlertGroupColumn => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
isVisible: false,
|
||||
type: AlertGroupColumnType.LABEL,
|
||||
})
|
||||
),
|
||||
];
|
||||
|
||||
const columns: { visible: AlertGroupColumn[]; hidden: AlertGroupColumn[] } = {
|
||||
visible: mergedColumns.filter((col) => col.isVisible),
|
||||
hidden: mergedColumns.filter((col) => !col.isVisible),
|
||||
};
|
||||
|
||||
try {
|
||||
await store.alertGroupStore.updateTableSettings(columns, false);
|
||||
await store.alertGroupStore.fetchTableSettings();
|
||||
|
||||
setIsModalOpen(false);
|
||||
setTimeout(() => forceOpenToggletip(), 0);
|
||||
setSearchResults([]);
|
||||
|
||||
inputRef.current.value = '';
|
||||
} catch (ex) {
|
||||
openErrorNotification('An error has occurred. Please try again');
|
||||
}
|
||||
}
|
||||
|
||||
function onInputChange() {
|
||||
const search = inputRef?.current?.value;
|
||||
|
||||
setSearchResults(
|
||||
availableKeysForSearching
|
||||
.filter((pair) => pair.name.indexOf(search) > -1)
|
||||
.map((pair) => ({ ...pair, isChecked: false, isCollapsed: true, values: undefined }))
|
||||
);
|
||||
}
|
||||
|
||||
function forceOpenToggletip() {
|
||||
document.getElementById('toggletip-button')?.click();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
export const getColumnsSelectorWrapperStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
input: css`
|
||||
margin-bottom: 16px;
|
||||
`,
|
||||
fieldRow: css`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: 'center';
|
||||
gap: 16px;
|
||||
`,
|
||||
content: css`
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
`,
|
||||
removalModal: css`
|
||||
max-width: 500px;
|
||||
`,
|
||||
totalValuesCount: css`
|
||||
margin-left: 16px;
|
||||
`,
|
||||
valuesBlock: css`
|
||||
margin-bottom: 12px;
|
||||
`,
|
||||
floatingContainer: css`
|
||||
position: relative;
|
||||
`,
|
||||
floatingContent: css`
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
right: 0;
|
||||
display: none;
|
||||
background-color: ${theme.colors.background.secondary};
|
||||
padding: 16px;
|
||||
z-index: 101;
|
||||
overflow: hidden;
|
||||
`,
|
||||
floatingContentVisible: css`
|
||||
display: block;
|
||||
`,
|
||||
checkboxAddOption: css`
|
||||
top: 3px;
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useStyles2, Button, HorizontalGroup, Icon, LoadingPlaceholder, Modal, VerticalGroup } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import Text from 'components/Text/Text';
|
||||
import { ColumnsSelector, convertColumnsToTableSettings } from 'containers/ColumnsSelector/ColumnsSelector';
|
||||
import { getColumnsSelectorWrapperStyles } from 'containers/ColumnsSelectorWrapper/ColumnsSelectorWrapper.styles';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { AlertGroupColumn } from 'models/alertgroup/alertgroup.types';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
import { WrapAutoLoadingState } from 'utils/decorators';
|
||||
|
||||
import { ColumnsModal } from './ColumnsModal';
|
||||
|
||||
interface ColumnsSelectorWrapperProps {}
|
||||
|
||||
const ColumnsSelectorWrapper: React.FC<ColumnsSelectorWrapperProps> = observer(() => {
|
||||
const [isConfirmRemovalModalOpen, setIsConfirmRemovalModalOpen] = useState(false);
|
||||
const [columnToBeRemoved, setColumnToBeRemoved] = useState<AlertGroupColumn>(undefined);
|
||||
const [isColumnAddModalOpen, setIsColumnAddModalOpen] = useState(false);
|
||||
const [isFloatingDisplayOpen, setIsFloatingDisplayOpen] = useState(false);
|
||||
|
||||
const [labelKeys, setLabelKeys] = useState<Array<ApiSchemas['LabelKey']>>([]);
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const wrappingFloatingContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const styles = useStyles2(getColumnsSelectorWrapperStyles);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
isColumnAddModalOpen &&
|
||||
(async function () {
|
||||
const keys = await store.alertGroupStore.loadLabelsKeys();
|
||||
setLabelKeys(keys);
|
||||
})();
|
||||
}, [isColumnAddModalOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', onFloatingDisplayClick);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', onFloatingDisplayClick);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const isRemoveLoading = store.loaderStore.isLoading(ActionKey.REMOVE_COLUMN_FROM_ALERT_GROUP);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ColumnsModal
|
||||
inputRef={inputRef}
|
||||
isModalOpen={isColumnAddModalOpen}
|
||||
labelKeys={labelKeys}
|
||||
setIsModalOpen={setIsColumnAddModalOpen}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
closeOnEscape={false}
|
||||
isOpen={isConfirmRemovalModalOpen}
|
||||
title={'Remove column'}
|
||||
onDismiss={onConfirmRemovalClose}
|
||||
className={styles.removalModal}
|
||||
>
|
||||
<VerticalGroup spacing="lg">
|
||||
<Text type="primary">Are you sure you want to remove column {columnToBeRemoved?.name}?</Text>
|
||||
|
||||
<HorizontalGroup justify="flex-end" spacing="md">
|
||||
<Button variant={'secondary'} onClick={onConfirmRemovalClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<WithPermissionControlTooltip userAction={UserActions.OtherSettingsWrite}>
|
||||
<Button
|
||||
disabled={isRemoveLoading}
|
||||
variant={'destructive'}
|
||||
onClick={WrapAutoLoadingState(onColumnRemovalClick, ActionKey.REMOVE_COLUMN_FROM_ALERT_GROUP)}
|
||||
>
|
||||
{isRemoveLoading ? <LoadingPlaceholder text="Loading..." className="loadingPlaceholder" /> : 'Remove'}
|
||||
</Button>
|
||||
</WithPermissionControlTooltip>
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
</Modal>
|
||||
|
||||
<div ref={wrappingFloatingContainerRef}>
|
||||
{!isColumnAddModalOpen && !isConfirmRemovalModalOpen ? (
|
||||
<div className={styles.floatingContainer}>
|
||||
{renderToggletipButton()}
|
||||
<div
|
||||
className={[styles.floatingContent, isFloatingDisplayOpen ? styles.floatingContentVisible : ''].join(' ')}
|
||||
>
|
||||
<ColumnsSelector
|
||||
onColumnAddModalOpen={() => setIsColumnAddModalOpen(!isColumnAddModalOpen)}
|
||||
onConfirmRemovalModalOpen={(column: AlertGroupColumn) => {
|
||||
setIsConfirmRemovalModalOpen(!isConfirmRemovalModalOpen);
|
||||
setColumnToBeRemoved(column);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
renderToggletipButton()
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
function onFloatingDisplayClick(event) {
|
||||
const element = wrappingFloatingContainerRef.current;
|
||||
const isInside = element?.contains(event.target as HTMLDivElement);
|
||||
|
||||
if (!isInside) {
|
||||
setIsFloatingDisplayOpen(false);
|
||||
}
|
||||
}
|
||||
|
||||
function onConfirmRemovalClose(): void {
|
||||
setIsConfirmRemovalModalOpen(false);
|
||||
forceOpenToggletip();
|
||||
}
|
||||
|
||||
async function onColumnRemovalClick(): Promise<void> {
|
||||
const columns = store.alertGroupStore.columns.filter((col) => col.id !== columnToBeRemoved.id);
|
||||
|
||||
await store.alertGroupStore.updateTableSettings(convertColumnsToTableSettings(columns), false);
|
||||
await store.alertGroupStore.fetchTableSettings();
|
||||
|
||||
setIsConfirmRemovalModalOpen(false);
|
||||
forceOpenToggletip();
|
||||
}
|
||||
|
||||
function renderToggletipButton() {
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant={'secondary'}
|
||||
icon="columns"
|
||||
id="toggletip-button"
|
||||
onClick={() => setIsFloatingDisplayOpen(!isFloatingDisplayOpen)}
|
||||
>
|
||||
<HorizontalGroup spacing="xs">
|
||||
Columns
|
||||
<Icon name="angle-down" />
|
||||
</HorizontalGroup>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function forceOpenToggletip() {
|
||||
document.getElementById('toggletip-button')?.click();
|
||||
}
|
||||
|
||||
export default ColumnsSelectorWrapper;
|
||||
|
|
@ -106,7 +106,12 @@ class IncidentsFilters extends Component<IncidentsFiltersProps, IncidentsFilters
|
|||
{filters.map((filterOption: FilterOption) => (
|
||||
<div key={filterOption.name} className={cx('filter')}>
|
||||
<Text type="secondary">{capitalCase(filterOption.name)}:</Text> {this.renderFilterOption(filterOption)}
|
||||
<IconButton size="sm" name="times" onClick={this.getDeleteFilterClickHandler(filterOption.name)} />
|
||||
<IconButton
|
||||
aria-label="Delete"
|
||||
size="sm"
|
||||
name="times"
|
||||
onClick={this.getDeleteFilterClickHandler(filterOption.name)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<Select
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
exports[`MobileAppConnection if we disconnect the app, it disconnects and fetches a new QR code 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -16,11 +16,11 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -29,7 +29,7 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -38,14 +38,14 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -70,7 +70,7 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
@ -102,11 +102,11 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -115,7 +115,7 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -124,7 +124,7 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="u-width-100 u-flex u-flex-center u-position-relative"
|
||||
|
|
@ -162,11 +162,11 @@ exports[`MobileAppConnection if we disconnect the app, it disconnects and fetche
|
|||
exports[`MobileAppConnection it shows a QR code if the app isn't already connected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -175,11 +175,11 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -188,7 +188,7 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -197,14 +197,14 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -229,7 +229,7 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
@ -261,15 +261,16 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-lq6a48"
|
||||
class="css-1yjvs5a"
|
||||
>
|
||||
Loading...
|
||||
|
||||
<div
|
||||
class="css-13pg8vy"
|
||||
class="css-1tqtz24"
|
||||
data-testid="Spinner"
|
||||
>
|
||||
<i
|
||||
aria-label="loading spinner"
|
||||
class="fa fa-spinner fa-spin fa-spin"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -284,11 +285,11 @@ exports[`MobileAppConnection it shows a QR code if the app isn't already connect
|
|||
exports[`MobileAppConnection it shows a loading message if it is currently disconnecting 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -297,11 +298,11 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -310,7 +311,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -319,14 +320,14 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -351,7 +352,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
@ -383,15 +384,16 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-lq6a48"
|
||||
class="css-1yjvs5a"
|
||||
>
|
||||
Loading...
|
||||
|
||||
<div
|
||||
class="css-13pg8vy"
|
||||
class="css-1tqtz24"
|
||||
data-testid="Spinner"
|
||||
>
|
||||
<i
|
||||
aria-label="loading spinner"
|
||||
class="fa fa-spinner fa-spin fa-spin"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -406,11 +408,11 @@ exports[`MobileAppConnection it shows a loading message if it is currently disco
|
|||
exports[`MobileAppConnection it shows a loading message if it is currently fetching the QR code 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -419,11 +421,11 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -432,7 +434,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -441,14 +443,14 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -473,7 +475,7 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
@ -505,15 +507,16 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-lq6a48"
|
||||
class="css-1yjvs5a"
|
||||
>
|
||||
Loading...
|
||||
|
||||
<div
|
||||
class="css-13pg8vy"
|
||||
class="css-1tqtz24"
|
||||
data-testid="Spinner"
|
||||
>
|
||||
<i
|
||||
aria-label="loading spinner"
|
||||
class="fa fa-spinner fa-spin fa-spin"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -528,11 +531,11 @@ exports[`MobileAppConnection it shows a loading message if it is currently fetch
|
|||
exports[`MobileAppConnection it shows a message when the mobile app is already connected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -541,11 +544,11 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -554,7 +557,7 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -563,14 +566,14 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -595,7 +598,7 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
@ -627,35 +630,23 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
>
|
||||
App connected
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-eyx4do icon"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M14.72,8.79l-4.29,4.3L8.78,11.44a1,1,0,1,0-1.41,1.41l2.35,2.36a1,1,0,0,0,.71.29,1,1,0,0,0,.7-.29l5-5a1,1,0,0,0,0-1.42A1,1,0,0,0,14.72,8.79ZM12,2A10,10,0,1,0,22,12,10,10,0,0,0,12,2Zm0,18a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -664,7 +655,7 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="disconnect__container"
|
||||
|
|
@ -674,12 +665,12 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
src="[object Object]"
|
||||
/>
|
||||
<button
|
||||
class="css-1ed0qk5-button disconnect-button"
|
||||
class="css-ttl745-button disconnect-button"
|
||||
data-testid="test__disconnect"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Disconnect
|
||||
</span>
|
||||
|
|
@ -697,11 +688,11 @@ exports[`MobileAppConnection it shows a message when the mobile app is already c
|
|||
exports[`MobileAppConnection it shows a warning when cloud is not connected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--secondary text--medium"
|
||||
|
|
@ -710,33 +701,21 @@ exports[`MobileAppConnection it shows a warning when cloud is not connected 1`]
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
class="root"
|
||||
href="/a/grafana-oncall-app/cloud"
|
||||
>
|
||||
<button
|
||||
class="css-b2ba3d-button"
|
||||
class="css-8b29hm-button"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-1gebccs"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18,10.82a1,1,0,0,0-1,1V19a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V8A1,1,0,0,1,5,7h7.18a1,1,0,0,0,0-2H5A3,3,0,0,0,2,8V19a3,3,0,0,0,3,3H16a3,3,0,0,0,3-3V11.82A1,1,0,0,0,18,10.82Zm3.92-8.2a1,1,0,0,0-.54-.54A1,1,0,0,0,21,2H15a1,1,0,0,0,0,2h3.59L8.29,14.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L20,5.41V9a1,1,0,0,0,2,0V3A1,1,0,0,0,21.92,2.62Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Connect Grafana Cloud OnCall
|
||||
</span>
|
||||
|
|
@ -750,11 +729,11 @@ exports[`MobileAppConnection it shows a warning when cloud is not connected 1`]
|
|||
exports[`MobileAppConnection it shows an error message if there was an error disconnecting the mobile app 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -763,11 +742,11 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -776,7 +755,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -785,14 +764,14 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -817,7 +796,7 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
@ -863,11 +842,11 @@ exports[`MobileAppConnection it shows an error message if there was an error dis
|
|||
exports[`MobileAppConnection it shows an error message if there was an error fetching the QR code 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="container"
|
||||
|
|
@ -876,11 +855,11 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
class="root root_bordered root_shadowed root--withBackGround container__box"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -889,7 +868,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -898,14 +877,14 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -930,7 +909,7 @@ exports[`MobileAppConnection it shows an error message if there was an error fet
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
exports[`DisconnectButton it renders properly 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="css-1ed0qk5-button disconnect-button"
|
||||
class="css-ttl745-button disconnect-button"
|
||||
data-testid="test__disconnect"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Disconnect
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
exports[`DownloadIcons it renders properly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium text--strong"
|
||||
|
|
@ -16,7 +16,7 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<span
|
||||
class="root text text--primary text--medium"
|
||||
|
|
@ -25,14 +25,14 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-ztyofd-layoutChildrenWrapper"
|
||||
class="css-12oo3x0-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://apps.apple.com/us/app/grafana-oncall-preview/id1669759048"
|
||||
|
|
@ -57,7 +57,7 @@ exports[`DownloadIcons it renders properly 1`] = `
|
|||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
href="https://play.google.com/store/apps/details?id=com.grafana.oncall.prod"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonData, and ONCALL_API_URL is passed in process.env, and there is an error calling selfHostedInstallPlugin, it sets an error message 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -20,32 +20,32 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Retry Sync
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -58,7 +58,7 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonData, or in process.env, updatePluginStatus is not called, and the configuration form is shown 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -66,7 +66,7 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
This page will help you configure the OnCall plugin 👋
|
||||
</p>
|
||||
<form
|
||||
class="css-xs0vux"
|
||||
class="css-1srg48i"
|
||||
data-testid="plugin-configuration-form"
|
||||
>
|
||||
<div
|
||||
|
|
@ -112,42 +112,44 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-8e5b3"
|
||||
class="css-1rplq84"
|
||||
>
|
||||
<div
|
||||
class="css-jt4xma-Label"
|
||||
class="css-l4ykjo-Label"
|
||||
>
|
||||
<label>
|
||||
<div
|
||||
class="css-xhqy0o"
|
||||
class="css-70qvj9"
|
||||
>
|
||||
OnCall backend URL
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="css-xcstkt-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="css-1w5c5dq-input-inputWrapper"
|
||||
class="css-1cvb0sk-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<input
|
||||
class="css-1mlczho-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
<div
|
||||
class="css-10lnb82-input-inputWrapper"
|
||||
>
|
||||
<input
|
||||
class="css-8tk2dk-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Connect
|
||||
</span>
|
||||
|
|
@ -159,7 +161,7 @@ exports[`PluginConfigPage If onCallApiUrl is not set in the plugin's meta jsonDa
|
|||
exports[`PluginConfigPage If onCallApiUrl is set, and updatePluginStatus returns an error, it sets an error message 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -176,32 +178,32 @@ exports[`PluginConfigPage If onCallApiUrl is set, and updatePluginStatus returns
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Retry Sync
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -214,7 +216,7 @@ exports[`PluginConfigPage If onCallApiUrl is set, and updatePluginStatus returns
|
|||
exports[`PluginConfigPage It doesn't make any network calls if the plugin configured query params are provided 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -228,33 +230,33 @@ exports[`PluginConfigPage It doesn't make any network calls if the plugin config
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
href="/a/grafana-oncall-app/"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Open Grafana OnCall
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -267,7 +269,7 @@ exports[`PluginConfigPage It doesn't make any network calls if the plugin config
|
|||
exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnected does not return an error. It displays properly the plugin connected items based on the license - License: OpenSource 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -281,33 +283,33 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
href="/a/grafana-oncall-app/"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Open Grafana OnCall
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -320,7 +322,7 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnected does not return an error. It displays properly the plugin connected items based on the license - License: some-other-license 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -334,18 +336,18 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-1j7sh2x-vertical-group"
|
||||
class="css-gjl87o-vertical-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<div
|
||||
class="css-jt4xma-Label"
|
||||
class="css-l4ykjo-Label"
|
||||
>
|
||||
<label>
|
||||
<div
|
||||
class="css-xhqy0o"
|
||||
class="css-70qvj9"
|
||||
>
|
||||
This is a cloud managed configuration.
|
||||
</div>
|
||||
|
|
@ -353,15 +355,15 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-bxa289-layoutChildrenWrapper"
|
||||
class="css-gxt817-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
href="/a/grafana-oncall-app/"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Open Grafana OnCall
|
||||
</span>
|
||||
|
|
@ -374,7 +376,7 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnected returns an error 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -391,32 +393,32 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Retry Sync
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -429,7 +431,7 @@ exports[`PluginConfigPage OnCallApiUrl is set, and checkTokenAndIfPluginIsConnec
|
|||
exports[`PluginConfigPage Plugin reset: successful - false 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -446,32 +448,32 @@ exports[`PluginConfigPage Plugin reset: successful - false 1`] = `
|
|||
</span>
|
||||
</pre>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Retry Sync
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -484,7 +486,7 @@ exports[`PluginConfigPage Plugin reset: successful - false 1`] = `
|
|||
exports[`PluginConfigPage Plugin reset: successful - true 1`] = `
|
||||
<div>
|
||||
<legend
|
||||
class="css-11wqcat"
|
||||
class="css-1w9pvsj"
|
||||
>
|
||||
Configure Grafana OnCall
|
||||
</legend>
|
||||
|
|
@ -492,7 +494,7 @@ exports[`PluginConfigPage Plugin reset: successful - true 1`] = `
|
|||
This page will help you configure the OnCall plugin 👋
|
||||
</p>
|
||||
<form
|
||||
class="css-xs0vux"
|
||||
class="css-1srg48i"
|
||||
data-testid="plugin-configuration-form"
|
||||
>
|
||||
<div
|
||||
|
|
@ -538,42 +540,44 @@ exports[`PluginConfigPage Plugin reset: successful - true 1`] = `
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-8e5b3"
|
||||
class="css-1rplq84"
|
||||
>
|
||||
<div
|
||||
class="css-jt4xma-Label"
|
||||
class="css-l4ykjo-Label"
|
||||
>
|
||||
<label>
|
||||
<div
|
||||
class="css-xhqy0o"
|
||||
class="css-70qvj9"
|
||||
>
|
||||
OnCall backend URL
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="css-xcstkt-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="css-1w5c5dq-input-inputWrapper"
|
||||
class="css-1cvb0sk-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<input
|
||||
class="css-1mlczho-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
<div
|
||||
class="css-10lnb82-input-inputWrapper"
|
||||
>
|
||||
<input
|
||||
class="css-8tk2dk-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Connect
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ exports[`ConfigurationForm It doesn't allow the user to submit if the URL is inv
|
|||
<body>
|
||||
<div>
|
||||
<form
|
||||
class="css-xs0vux"
|
||||
class="css-1srg48i"
|
||||
data-testid="plugin-configuration-form"
|
||||
>
|
||||
<div
|
||||
|
|
@ -50,68 +50,58 @@ exports[`ConfigurationForm It doesn't allow the user to submit if the URL is inv
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-8e5b3"
|
||||
class="css-1rplq84"
|
||||
>
|
||||
<div
|
||||
class="css-jt4xma-Label"
|
||||
class="css-l4ykjo-Label"
|
||||
>
|
||||
<label>
|
||||
<div
|
||||
class="css-xhqy0o"
|
||||
class="css-70qvj9"
|
||||
>
|
||||
OnCall backend URL
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="css-1wz1ggz-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="css-1w5c5dq-input-inputWrapper"
|
||||
class="css-1skhtb9-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<input
|
||||
class="css-12lx392-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
<div
|
||||
class="css-10lnb82-input-inputWrapper"
|
||||
>
|
||||
<input
|
||||
class="css-11mwy6h-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="css-1gd2lua"
|
||||
class="css-1fhgjcy"
|
||||
>
|
||||
<div
|
||||
class="css-mw0th3"
|
||||
class="css-9z7wq3"
|
||||
role="alert"
|
||||
>
|
||||
<div
|
||||
class="css-wf08df-Icon"
|
||||
>
|
||||
<svg
|
||||
class="css-1ah41zt"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12,16a1,1,0,1,0,1,1A1,1,0,0,0,12,16Zm10.67,1.47-8.05-14a3,3,0,0,0-5.24,0l-8,14A3,3,0,0,0,3.94,22H20.06a3,3,0,0,0,2.61-4.53Zm-1.73,2a1,1,0,0,1-.88.51H3.94a1,1,0,0,1-.88-.51,1,1,0,0,1,0-1l8-14a1,1,0,0,1,1.78,0l8.05,14A1,1,0,0,1,20.94,19.49ZM12,8a1,1,0,0,0-1,1v4a1,1,0,0,0,2,0V9A1,1,0,0,0,12,8Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
class="css-1j2891d-Icon"
|
||||
/>
|
||||
Must be a valid URL
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
disabled=""
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Connect
|
||||
</span>
|
||||
|
|
@ -125,7 +115,7 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
<body>
|
||||
<div>
|
||||
<form
|
||||
class="css-xs0vux"
|
||||
class="css-1srg48i"
|
||||
data-testid="plugin-configuration-form"
|
||||
>
|
||||
<div
|
||||
|
|
@ -171,32 +161,34 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="css-8e5b3"
|
||||
class="css-1rplq84"
|
||||
>
|
||||
<div
|
||||
class="css-jt4xma-Label"
|
||||
class="css-l4ykjo-Label"
|
||||
>
|
||||
<label>
|
||||
<div
|
||||
class="css-xhqy0o"
|
||||
class="css-70qvj9"
|
||||
>
|
||||
OnCall backend URL
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="css-xcstkt-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="css-1w5c5dq-input-inputWrapper"
|
||||
class="css-1cvb0sk-input-wrapper"
|
||||
data-testid="input-wrapper"
|
||||
>
|
||||
<input
|
||||
class="css-1mlczho-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
<div
|
||||
class="css-10lnb82-input-inputWrapper"
|
||||
>
|
||||
<input
|
||||
class="css-8tk2dk-input-input"
|
||||
data-testid="onCallApiUrl"
|
||||
name="onCallApiUrl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -263,11 +255,11 @@ exports[`ConfigurationForm It shows an error message if the self hosted plugin A
|
|||
</span>
|
||||
</div>
|
||||
<button
|
||||
class="css-z53gi5-button"
|
||||
class="css-td06pi-button"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Connect
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ exports[`RemoveCurrentConfigurationButton It renders properly when disabled 1`]
|
|||
<body>
|
||||
<div>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
disabled=""
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
@ -22,11 +22,11 @@ exports[`RemoveCurrentConfigurationButton It renders properly when enabled 1`] =
|
|||
<body>
|
||||
<div>
|
||||
<button
|
||||
class="css-1ed0qk5-button"
|
||||
class="css-ttl745-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Remove current configuration
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -452,7 +452,7 @@ const RotationForm = observer((props: RotationFormProps) => {
|
|||
onClick={() => setShowDeleteRotationConfirmation(true)}
|
||||
/>
|
||||
)}
|
||||
<IconButton variant="secondary" className={cx('drag-handler')} name="draggabledots" />
|
||||
<IconButton aria-label="Drag" variant="secondary" className={cx('drag-handler')} name="draggabledots" />
|
||||
<IconButton
|
||||
name="times"
|
||||
variant="secondary"
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
|
|||
<IconButton variant="secondary" tooltip="Delete" name="trash-alt" onClick={handleDeleteClick} />
|
||||
</WithConfirm>
|
||||
)}
|
||||
<IconButton variant="secondary" className={cx('drag-handler')} name="draggabledots" />
|
||||
<IconButton aria-label="Drag" variant="secondary" className={cx('drag-handler')} name="draggabledots" />
|
||||
<IconButton
|
||||
name="times"
|
||||
variant="secondary"
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ const ShiftSwapForm = (props: ShiftSwapFormProps) => {
|
|||
</WithConfirm>
|
||||
</WithPermissionControlTooltip>
|
||||
)}
|
||||
<IconButton variant="secondary" className={cx('drag-handler')} name="draggabledots" />
|
||||
<IconButton aria-label="Drag" variant="secondary" className={cx('drag-handler')} name="draggabledots" />
|
||||
<IconButton name="times" variant="secondary" tooltip="Close" onClick={handleHide} />
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ const TeamModal = ({ teamId, onHide }: TeamModalProps) => {
|
|||
{ label: 'Team members and admins', value: '0' },
|
||||
]}
|
||||
value={shareResourceToAll}
|
||||
onChange={setShareResourceToAll}
|
||||
onChange={setShareResourceToAll as (res: string) => void}
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
<Text>Edit custom payload</Text>
|
||||
|
||||
<HorizontalGroup>
|
||||
<IconButton name="times" onClick={returnToListView} />
|
||||
<IconButton aria-label="List View" name="times" onClick={returnToListView} />
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
|
|
@ -263,7 +263,7 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
<Text>Edit custom payload</Text>
|
||||
|
||||
<HorizontalGroup>
|
||||
<IconButton name="times" onClick={() => returnToListView()} />
|
||||
<IconButton aria-label="List View" name="times" onClick={() => returnToListView()} />
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
|
|
@ -292,8 +292,8 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
<Text>{selectedTitle}</Text>
|
||||
</div>
|
||||
<div className={cx('title-action-icons')}>
|
||||
<IconButton name="edit" onClick={() => setIsEditMode(true)} />
|
||||
<IconButton name="times" onClick={() => returnToListView()} />
|
||||
<IconButton aria-label="Edit" name="edit" onClick={() => setIsEditMode(true)} />
|
||||
<IconButton aria-label="List View" name="times" onClick={() => returnToListView()} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import qs from 'query-string';
|
|||
|
||||
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
|
||||
import BaseStore from 'models/base_store';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { User } from 'models/user/user.types';
|
||||
import { makeRequest } from 'network';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
|
|
@ -11,8 +12,9 @@ import { RootStore } from 'state';
|
|||
import { SelectOption } from 'state/types';
|
||||
import { openErrorNotification, refreshPageError, showApiError } from 'utils';
|
||||
import LocationHelper from 'utils/LocationHelper';
|
||||
import { AutoLoadingState } from 'utils/decorators';
|
||||
|
||||
import { Alert, AlertAction, IncidentStatus } from './alertgroup.types';
|
||||
import { AlertGroupColumn, Alert, AlertAction, IncidentStatus } from './alertgroup.types';
|
||||
|
||||
export class AlertGroupStore extends BaseStore {
|
||||
@observable.shallow
|
||||
|
|
@ -69,6 +71,12 @@ export class AlertGroupStore extends BaseStore {
|
|||
@observable
|
||||
liveUpdatesPaused = false;
|
||||
|
||||
@observable
|
||||
columns: AlertGroupColumn[] = [];
|
||||
|
||||
@observable
|
||||
isDefaultColumnOrder = false;
|
||||
|
||||
constructor(rootStore: RootStore) {
|
||||
super(rootStore);
|
||||
|
||||
|
|
@ -429,21 +437,64 @@ export class AlertGroupStore extends BaseStore {
|
|||
}
|
||||
|
||||
@action
|
||||
public async loadLabelsKeys() {
|
||||
return await makeRequest(`/alertgroups/labels/keys/`, {});
|
||||
async fetchTableSettings(): Promise<void> {
|
||||
const tableSettings = await makeRequest('/alertgroup_table_settings', {});
|
||||
|
||||
const { hidden, visible, default: isDefaultOrder } = tableSettings;
|
||||
|
||||
this.isDefaultColumnOrder = isDefaultOrder;
|
||||
this.columns = [
|
||||
...visible.map((item: AlertGroupColumn): AlertGroupColumn => ({ ...item, isVisible: true })),
|
||||
...hidden.map((item: AlertGroupColumn): AlertGroupColumn => ({ ...item, isVisible: false })),
|
||||
];
|
||||
}
|
||||
|
||||
@action
|
||||
public async loadValuesForLabelKey(key: ApiSchemas['LabelKey']['id'], search = '') {
|
||||
@AutoLoadingState(ActionKey.ADD_NEW_COLUMN_TO_ALERT_GROUP)
|
||||
async updateTableSettings(
|
||||
columns: { visible: AlertGroupColumn[]; hidden: AlertGroupColumn[] },
|
||||
isUserUpdate: boolean
|
||||
): Promise<void> {
|
||||
const method = isUserUpdate ? 'PUT' : 'POST';
|
||||
|
||||
const { default: isDefaultOrder } = await makeRequest('/alertgroup_table_settings', {
|
||||
method,
|
||||
data: { ...columns },
|
||||
});
|
||||
|
||||
this.isDefaultColumnOrder = isDefaultOrder;
|
||||
}
|
||||
|
||||
@action
|
||||
async resetTableSettings(): Promise<void> {
|
||||
return await makeRequest('/alertgroup_table_settings/reset', { method: 'POST' }).catch(() =>
|
||||
openErrorNotification('There was an error resetting the table settings')
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
async loadLabelsKeys(): Promise<Array<ApiSchemas['LabelKey']>> {
|
||||
return await makeRequest(`/alertgroups/labels/keys/`, {}).catch(() =>
|
||||
openErrorNotification('There was an error processing your request')
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
async loadValuesForLabelKey(
|
||||
key: ApiSchemas['LabelKey']['id'],
|
||||
search = ''
|
||||
): Promise<{ key: ApiSchemas['LabelKey']; values: Array<ApiSchemas['LabelValue']> }> {
|
||||
if (!key) {
|
||||
return [];
|
||||
return { key: undefined, values: [] };
|
||||
}
|
||||
|
||||
const result = await makeRequest(`/alertgroups/labels/id/${key}`, {
|
||||
params: { search },
|
||||
});
|
||||
|
||||
const filteredValues = result.values.filter((v) => v.name.toLowerCase().includes(search.toLowerCase())); // TODO remove after backend search implementation
|
||||
const filteredValues = result.values.filter((v: ApiSchemas['LabelValue']) =>
|
||||
v.name.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
|
||||
return { ...result, values: filteredValues };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,18 @@ export interface Alert {
|
|||
undoAction?: AlertAction;
|
||||
}
|
||||
|
||||
export interface AlertGroupColumn {
|
||||
id: string;
|
||||
name: string;
|
||||
isVisible: boolean;
|
||||
type?: AlertGroupColumnType;
|
||||
}
|
||||
|
||||
export enum AlertGroupColumnType {
|
||||
DEFAULT = 'default',
|
||||
LABEL = 'label',
|
||||
}
|
||||
|
||||
interface RenderForWeb {
|
||||
message: any;
|
||||
title: any;
|
||||
|
|
|
|||
5
grafana-plugin/src/models/loader/action-keys.ts
Normal file
5
grafana-plugin/src/models/loader/action-keys.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export enum ActionKey {
|
||||
ADD_NEW_COLUMN_TO_ALERT_GROUP = 'ADD_NEW_COLUMN_TO_ALERT_GROUP',
|
||||
REMOVE_COLUMN_FROM_ALERT_GROUP = 'REMOVE_COLUMN_FROM_ALERT_GROUP',
|
||||
RESET_COLUMNS_FROM_ALERT_GROUP = 'RESET_COLUMNS_FROM_ALERT_GROUP',
|
||||
}
|
||||
21
grafana-plugin/src/models/loader/loader.ts
Normal file
21
grafana-plugin/src/models/loader/loader.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { action, observable } from 'mobx';
|
||||
|
||||
interface LoadingResult {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
||||
class LoaderStoreClass {
|
||||
@observable
|
||||
items: LoadingResult = {};
|
||||
|
||||
@action
|
||||
setLoadingAction(actionKey: string, isLoading: boolean) {
|
||||
this.items[actionKey] = isLoading;
|
||||
}
|
||||
|
||||
isLoading(actionKey: string): boolean {
|
||||
return !!this.items[actionKey];
|
||||
}
|
||||
}
|
||||
|
||||
export const LoaderStore = new LoaderStoreClass();
|
||||
|
|
@ -177,7 +177,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
|
|||
</GList>
|
||||
) : (
|
||||
<VerticalGroup>
|
||||
<Text type="primary" className={cx('loading')}>
|
||||
<Text type="primary" className={cx('loadingPlaceholder')}>
|
||||
Loading...
|
||||
</Text>
|
||||
</VerticalGroup>
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
|
|||
<HorizontalGroup justify="space-between">
|
||||
<HorizontalGroup className={cx('title')}>
|
||||
<PluginLink query={{ page: 'alert-groups', ...query }}>
|
||||
<IconButton name="arrow-left" size="xl" />
|
||||
<IconButton aria-label="Go Back" name="arrow-left" size="xl" />
|
||||
</PluginLink>
|
||||
{/* @ts-ignore*/}
|
||||
<HorizontalGroup align="baseline">
|
||||
|
|
@ -765,7 +765,7 @@ function GroupedIncident({ incident, datetimeReference }: { incident: GroupedAle
|
|||
<div className={cx('incident-row-right')}>
|
||||
<HorizontalGroup wrap={false} justify={'flex-end'}>
|
||||
<Tooltip placement="top" content="Alert Payload">
|
||||
<IconButton name="arrow" onClick={() => openIncidentResponse(incident)} />
|
||||
<IconButton aria-label="Alert Payload" name="arrow" onClick={() => openIncidentResponse(incident)} />
|
||||
</Tooltip>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,14 +11,29 @@
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.fields-dropdown {
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
align-items: center;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.above-incidents-table {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bulk-actions {
|
||||
.bulk-actions-container {
|
||||
margin: 10px 0 10px 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.bulk-actions-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.other-users {
|
||||
|
|
@ -41,6 +56,10 @@
|
|||
right: 0;
|
||||
}
|
||||
|
||||
.btn-results {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* filter cards */
|
||||
|
||||
.cards {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import React, { SyntheticEvent } from 'react';
|
||||
|
||||
import { Button, HorizontalGroup, Icon, VerticalGroup } from '@grafana/ui';
|
||||
import { LabelTag } from '@grafana/labels';
|
||||
import { Button, HorizontalGroup, Icon, RadioButtonGroup, VerticalGroup } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { capitalize } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
import moment from 'moment-timezone';
|
||||
import Emoji from 'react-emoji-render';
|
||||
|
|
@ -11,25 +13,37 @@ import CardButton from 'components/CardButton/CardButton';
|
|||
import CursorPagination from 'components/CursorPagination/CursorPagination';
|
||||
import GTable from 'components/GTable/GTable';
|
||||
import IntegrationLogo from 'components/IntegrationLogo/IntegrationLogo';
|
||||
import LabelsTooltipBadge from 'components/LabelsTooltipBadge/LabelsTooltipBadge';
|
||||
import ManualAlertGroup from 'components/ManualAlertGroup/ManualAlertGroup';
|
||||
import PluginLink from 'components/PluginLink/PluginLink';
|
||||
import RenderConditionally from 'components/RenderConditionally/RenderConditionally';
|
||||
import Text from 'components/Text/Text';
|
||||
import TextEllipsisTooltip from 'components/TextEllipsisTooltip/TextEllipsisTooltip';
|
||||
import TooltipBadge from 'components/TooltipBadge/TooltipBadge';
|
||||
import Tutorial from 'components/Tutorial/Tutorial';
|
||||
import { TutorialStep } from 'components/Tutorial/Tutorial.types';
|
||||
import ColumnsSelectorWrapper from 'containers/ColumnsSelectorWrapper/ColumnsSelectorWrapper';
|
||||
import { IncidentsFiltersType } from 'containers/IncidentsFilters/IncidentFilters.types';
|
||||
import RemoteFilters from 'containers/RemoteFilters/RemoteFilters';
|
||||
import TeamName from 'containers/TeamName/TeamName';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { Alert, Alert as AlertType, AlertAction, IncidentStatus } from 'models/alertgroup/alertgroup.types';
|
||||
import {
|
||||
Alert,
|
||||
Alert as AlertType,
|
||||
AlertAction,
|
||||
IncidentStatus,
|
||||
AlertGroupColumn,
|
||||
AlertGroupColumnType,
|
||||
} from 'models/alertgroup/alertgroup.types';
|
||||
import { LabelKeyValue } from 'models/label/label.types';
|
||||
import { renderRelatedUsers } from 'pages/incident/Incident.helpers';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { PageProps, WithStoreProps } from 'state/types';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
import LocationHelper from 'utils/LocationHelper';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
import { PAGE, PLUGIN_ROOT, TEXT_ELLIPSIS_CLASS } from 'utils/consts';
|
||||
import { INCIDENT_HORIZONTAL_SCROLLING_STORAGE, PAGE, PLUGIN_ROOT, TEXT_ELLIPSIS_CLASS } from 'utils/consts';
|
||||
import { getItem, setItem } from 'utils/localStorage';
|
||||
import { TableColumn } from 'utils/types';
|
||||
|
||||
import styles from './Incidents.module.scss';
|
||||
import { IncidentDropdown } from './parts/IncidentDropdown';
|
||||
|
|
@ -49,6 +63,8 @@ interface IncidentsPageState {
|
|||
filters?: Record<string, any>;
|
||||
pagination: Pagination;
|
||||
showAddAlertGroupForm: boolean;
|
||||
isSelectorColumnMenuOpen: boolean;
|
||||
isHorizontalScrolling: boolean;
|
||||
}
|
||||
|
||||
const POLLING_NUM_SECONDS = 15;
|
||||
|
|
@ -59,6 +75,14 @@ const PAGINATION_OPTIONS = [
|
|||
{ label: '100', value: 100 },
|
||||
];
|
||||
|
||||
const TABLE_SCROLL_OPTIONS: Array<{ value: boolean; icon: string }> = [
|
||||
{ value: false, icon: 'wrap-text' },
|
||||
{
|
||||
value: true,
|
||||
icon: 'arrow-from-right',
|
||||
},
|
||||
];
|
||||
|
||||
@observer
|
||||
class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState> {
|
||||
constructor(props: IncidentsPageProps) {
|
||||
|
|
@ -82,16 +106,23 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
start,
|
||||
end: start + pageSize,
|
||||
},
|
||||
isSelectorColumnMenuOpen: true,
|
||||
isHorizontalScrolling: getItem(INCIDENT_HORIZONTAL_SCROLLING_STORAGE) || false,
|
||||
};
|
||||
}
|
||||
|
||||
private pollingIntervalId: NodeJS.Timer = undefined;
|
||||
|
||||
componentDidMount() {
|
||||
const { alertGroupStore } = this.props.store;
|
||||
const { store } = this.props;
|
||||
const { alertGroupStore } = store;
|
||||
|
||||
alertGroupStore.updateBulkActions();
|
||||
alertGroupStore.updateSilenceOptions();
|
||||
|
||||
if (store.hasFeature(AppFeature.Labels)) {
|
||||
alertGroupStore.fetchTableSettings();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
|
|
@ -335,6 +366,11 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
);
|
||||
};
|
||||
|
||||
onEnableHorizontalScroll = (value: boolean) => {
|
||||
setItem(INCIDENT_HORIZONTAL_SCROLLING_STORAGE, value);
|
||||
this.setState({ isHorizontalScrolling: value });
|
||||
};
|
||||
|
||||
handleChangeItemsPerPage = (value: number) => {
|
||||
const { store } = this.props;
|
||||
|
||||
|
|
@ -357,7 +393,7 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
};
|
||||
|
||||
renderBulkActions = () => {
|
||||
const { selectedIncidentIds, affectedRows } = this.state;
|
||||
const { selectedIncidentIds, affectedRows, isHorizontalScrolling } = this.state;
|
||||
const { store } = this.props;
|
||||
|
||||
if (!store.alertGroupStore.bulkActions) {
|
||||
|
|
@ -373,8 +409,8 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
|
||||
return (
|
||||
<div className={cx('above-incidents-table')}>
|
||||
<div className={cx('bulk-actions')}>
|
||||
<HorizontalGroup>
|
||||
<div className={cx('bulk-actions-container')}>
|
||||
<div className={cx('bulk-actions-list')}>
|
||||
{'resolve' in store.alertGroupStore.bulkActions && (
|
||||
<WithPermissionControlTooltip key="resolve" userAction={UserActions.AlertGroupsWrite}>
|
||||
<Button
|
||||
|
|
@ -421,27 +457,42 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
? `${selectedIncidentIds.length} Alert Group${selectedIncidentIds.length > 1 ? 's' : ''} selected`
|
||||
: 'No Alert Groups selected'}
|
||||
</Text>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
{hasInvalidatedAlert && (
|
||||
<div className={cx('out-of-date')}>
|
||||
<Text type="secondary">Results out of date</Text>
|
||||
<Button
|
||||
style={{ marginLeft: '8px' }}
|
||||
disabled={store.alertGroupStore.alertGroupsLoading}
|
||||
variant="primary"
|
||||
onClick={this.onIncidentsUpdateClick}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={cx('fields-dropdown')}>
|
||||
<RenderConditionally shouldRender={hasInvalidatedAlert}>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<Text type="secondary">Results out of date</Text>
|
||||
<Button
|
||||
className={cx('btn-results')}
|
||||
disabled={store.alertGroupStore.alertGroupsLoading}
|
||||
variant="primary"
|
||||
onClick={this.onIncidentsUpdateClick}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
</RenderConditionally>
|
||||
|
||||
<RenderConditionally shouldRender={store.hasFeature(AppFeature.Labels)}>
|
||||
<RadioButtonGroup
|
||||
options={TABLE_SCROLL_OPTIONS}
|
||||
value={isHorizontalScrolling}
|
||||
onChange={this.onEnableHorizontalScroll}
|
||||
/>
|
||||
</RenderConditionally>
|
||||
|
||||
<RenderConditionally shouldRender={store.hasFeature(AppFeature.Labels)}>
|
||||
<ColumnsSelectorWrapper />
|
||||
</RenderConditionally>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
renderTable() {
|
||||
const { selectedIncidentIds, pagination } = this.state;
|
||||
const { selectedIncidentIds, pagination, isHorizontalScrolling } = this.state;
|
||||
const { alertGroupStore, filtersStore } = this.props.store;
|
||||
|
||||
const { results, prev, next } = alertGroupStore.getAlertSearchResult('default');
|
||||
|
|
@ -468,6 +519,8 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
);
|
||||
}
|
||||
|
||||
const tableColumns = this.getTableColumns();
|
||||
|
||||
return (
|
||||
<div className={cx('root')}>
|
||||
{this.renderBulkActions()}
|
||||
|
|
@ -481,7 +534,9 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
}}
|
||||
rowKey="pk"
|
||||
data={results}
|
||||
columns={this.getTableColumns()}
|
||||
columns={tableColumns}
|
||||
tableLayout="auto"
|
||||
scroll={{ x: isHorizontalScrolling ? `${Math.max(2000, tableColumns.length * 250)}px` : true }}
|
||||
/>
|
||||
{this.shouldShowPagination() && (
|
||||
<div className={cx('pagination')}>
|
||||
|
|
@ -503,7 +558,7 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
renderId(record: AlertType) {
|
||||
return (
|
||||
<TextEllipsisTooltip placement="top" content={`#${record.inside_organization_number}`}>
|
||||
<Text type="secondary" className={cx(TEXT_ELLIPSIS_CLASS)}>
|
||||
<Text type="secondary" className={cx(TEXT_ELLIPSIS_CLASS, 'overflow-child--line-1')}>
|
||||
#{record.inside_organization_number}
|
||||
</Text>
|
||||
</TextEllipsisTooltip>
|
||||
|
|
@ -518,7 +573,7 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
return (
|
||||
<div>
|
||||
<TextEllipsisTooltip placement="top" content={record.render_for_web.title}>
|
||||
<Text type="link" size="medium" className={cx('overflow-parent')}>
|
||||
<Text type="link" size="medium" className={cx('overflow-parent')} data-testid="integration-url">
|
||||
<PluginLink
|
||||
query={{
|
||||
page: 'alert-groups',
|
||||
|
|
@ -555,7 +610,11 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
content={record?.alert_receive_channel?.verbal_name || ''}
|
||||
>
|
||||
<IntegrationLogo integration={integration} scale={0.1} />
|
||||
<Emoji className={cx(TEXT_ELLIPSIS_CLASS)} text={record.alert_receive_channel?.verbal_name || ''} />
|
||||
<Emoji
|
||||
className={cx(TEXT_ELLIPSIS_CLASS)}
|
||||
text={record.alert_receive_channel?.verbal_name || ''}
|
||||
data-testid="integration-name"
|
||||
/>
|
||||
</TextEllipsisTooltip>
|
||||
);
|
||||
};
|
||||
|
|
@ -574,16 +633,60 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
);
|
||||
};
|
||||
|
||||
renderStartedAt(alert: AlertType) {
|
||||
renderStartedAt = (alert: AlertType) => {
|
||||
const m = moment(alert.started_at);
|
||||
const { isHorizontalScrolling } = this.state;
|
||||
|
||||
const date = m.format('MMM DD, YYYY');
|
||||
const time = m.format('HH:mm');
|
||||
|
||||
if (isHorizontalScrolling) {
|
||||
// display date as 1 line
|
||||
return (
|
||||
<Text type="secondary">
|
||||
{date} {time}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<VerticalGroup spacing="none">
|
||||
<Text type="secondary">{m.format('MMM DD, YYYY')}</Text>
|
||||
<Text type="secondary">{m.format('HH:mm')}</Text>
|
||||
<Text type="secondary">{date}</Text>
|
||||
<Text type="secondary">{time}</Text>
|
||||
</VerticalGroup>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderLabels = (item: AlertType) => {
|
||||
if (!item.labels.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TooltipBadge
|
||||
borderType="secondary"
|
||||
icon="tag-alt"
|
||||
addPadding
|
||||
text={item.labels?.length}
|
||||
tooltipContent={
|
||||
<VerticalGroup spacing="sm">
|
||||
{item.labels.map((label) => (
|
||||
<HorizontalGroup spacing="sm" key={label.key.id}>
|
||||
<LabelTag label={label.key.name} value={label.value.name} key={label.key.id} />
|
||||
<Button
|
||||
size="sm"
|
||||
icon="filter"
|
||||
tooltip="Apply filter"
|
||||
variant="secondary"
|
||||
onClick={this.getApplyLabelFilterClickHandler(label)}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
))}
|
||||
</VerticalGroup>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderTeam(record: AlertType, teams: any) {
|
||||
return (
|
||||
|
|
@ -593,6 +696,41 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
);
|
||||
}
|
||||
|
||||
getApplyLabelFilterClickHandler = (label: LabelKeyValue) => {
|
||||
const {
|
||||
store: { filtersStore },
|
||||
} = this.props;
|
||||
|
||||
return () => {
|
||||
const {
|
||||
filters: { label: oldLabelFilter = [] },
|
||||
} = this.state;
|
||||
|
||||
const labelToAddString = `${label.key.id}:${label.value.id}`;
|
||||
if (oldLabelFilter.some((label) => label === labelToAddString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newLabelFilter = [...oldLabelFilter, labelToAddString];
|
||||
|
||||
LocationHelper.update({ label: newLabelFilter }, 'partial');
|
||||
|
||||
filtersStore.setNeedToParseFilters(true);
|
||||
};
|
||||
};
|
||||
|
||||
renderCustomColumn = (column: AlertGroupColumn, alert: AlertType) => {
|
||||
const matchingLabel = alert.labels?.find((label) => label.key.name === column.name)?.value.name;
|
||||
|
||||
return (
|
||||
<TextEllipsisTooltip placement="top" content={matchingLabel}>
|
||||
<Text type="secondary" className={cx(TEXT_ELLIPSIS_CLASS, 'overflow-child--line-1')}>
|
||||
{matchingLabel}
|
||||
</Text>
|
||||
</TextEllipsisTooltip>
|
||||
);
|
||||
};
|
||||
|
||||
shouldShowPagination() {
|
||||
const { alertGroupStore } = this.props.store;
|
||||
|
||||
|
|
@ -609,78 +747,90 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
|
|||
});
|
||||
};
|
||||
|
||||
getTableColumns(): Array<{ width: string; title: string; key: string; render }> {
|
||||
const {
|
||||
store: { filtersStore, grafanaTeamStore, hasFeature },
|
||||
} = this.props;
|
||||
getTableColumns(): TableColumn[] {
|
||||
const { store } = this.props;
|
||||
const { isHorizontalScrolling } = this.state;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
width: '140px',
|
||||
title: 'Status',
|
||||
key: 'time',
|
||||
render: this.renderStatus,
|
||||
},
|
||||
{
|
||||
width: '10%',
|
||||
const columnMapping: { [key: string]: TableColumn } = {
|
||||
ID: {
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
render: this.renderId,
|
||||
width: isHorizontalScrolling ? '100px' : '10%',
|
||||
},
|
||||
{
|
||||
width: '35%',
|
||||
title: 'Title',
|
||||
key: 'title',
|
||||
render: this.renderTitle,
|
||||
Status: {
|
||||
title: 'Status',
|
||||
key: 'time',
|
||||
render: this.renderStatus,
|
||||
width: '140px',
|
||||
},
|
||||
{
|
||||
width: '5%',
|
||||
Alerts: {
|
||||
title: 'Alerts',
|
||||
key: 'alerts',
|
||||
render: this.renderAlertsCounter,
|
||||
width: '100px',
|
||||
},
|
||||
{
|
||||
width: '15%',
|
||||
Integration: {
|
||||
title: 'Integration',
|
||||
key: 'source',
|
||||
key: 'integration',
|
||||
render: this.renderSource,
|
||||
width: isHorizontalScrolling ? undefined : '15%',
|
||||
},
|
||||
{
|
||||
width: '10%',
|
||||
Title: {
|
||||
title: 'Title',
|
||||
key: 'title',
|
||||
render: this.renderTitle,
|
||||
width: isHorizontalScrolling ? undefined : '35%',
|
||||
},
|
||||
Created: {
|
||||
title: 'Created',
|
||||
key: 'created',
|
||||
render: this.renderStartedAt,
|
||||
width: isHorizontalScrolling ? undefined : '10%',
|
||||
},
|
||||
{
|
||||
width: '10%',
|
||||
Team: {
|
||||
title: 'Team',
|
||||
key: 'team',
|
||||
render: (item: AlertType) => this.renderTeam(item, grafanaTeamStore.items),
|
||||
render: (item: AlertType) => this.renderTeam(item, store.grafanaTeamStore.items),
|
||||
width: isHorizontalScrolling ? undefined : '10%',
|
||||
},
|
||||
{
|
||||
width: '15%',
|
||||
Users: {
|
||||
title: 'Users',
|
||||
key: 'users',
|
||||
render: renderRelatedUsers,
|
||||
width: isHorizontalScrolling ? undefined : '15%',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
if (hasFeature(AppFeature.Labels)) {
|
||||
columns.splice(-2, 0, {
|
||||
width: '5%',
|
||||
if (store.hasFeature(AppFeature.Labels)) {
|
||||
// add labels specific column if enabled
|
||||
columnMapping['Labels'] = {
|
||||
width: '60px',
|
||||
title: 'Labels',
|
||||
key: 'labels',
|
||||
render: ({ labels }: AlertType) => (
|
||||
<LabelsTooltipBadge
|
||||
labels={labels}
|
||||
onClick={(label) => filtersStore.applyLabelFilter(label, PAGE.Incidents)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
columns.find((column) => column.key === 'title').width = '30%';
|
||||
render: this.renderLabels,
|
||||
};
|
||||
} else {
|
||||
// no filtering needed if we don't have Labels enabled
|
||||
return Object.keys(columnMapping).map((col) => columnMapping[col]);
|
||||
}
|
||||
|
||||
return columns;
|
||||
const mappedColumns: TableColumn[] = store.alertGroupStore.columns
|
||||
.filter((col) => col.isVisible)
|
||||
.map((column: AlertGroupColumn): TableColumn => {
|
||||
if (column.type === AlertGroupColumnType.DEFAULT && columnMapping[column.name]) {
|
||||
return columnMapping[column.name];
|
||||
}
|
||||
|
||||
return {
|
||||
width: isHorizontalScrolling ? '200px' : '10%',
|
||||
title: capitalize(column.name),
|
||||
key: column.id,
|
||||
render: (item: AlertType) => this.renderCustomColumn(column, item),
|
||||
};
|
||||
});
|
||||
|
||||
return mappedColumns;
|
||||
}
|
||||
|
||||
getOnActionButtonClick = (incidentId: string, action: AlertAction): ((e: SyntheticEvent) => Promise<void>) => {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ class Integration extends React.Component<IntegrationProps, IntegrationState> {
|
|||
|
||||
<div className={cx('integration__heading-container')}>
|
||||
<PluginLink query={{ page: 'integrations', ...query }} className={cx('back-arrow')}>
|
||||
<IconButton name="arrow-left" size="xl" />
|
||||
<IconButton aria-label="Go Back" name="arrow-left" size="xl" />
|
||||
</PluginLink>
|
||||
<h2 className={cx('integration__name')}>
|
||||
<Emoji text={alertReceiveChannel.verbal_name} />
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
<HorizontalGroup justify="space-between">
|
||||
<div className={cx('title')}>
|
||||
<PluginLink query={{ page: 'schedules', ...query }}>
|
||||
<IconButton style={{ marginTop: '5px' }} name="arrow-left" size="xl" />
|
||||
<IconButton className="button-back" aria-label="Go Back" name="arrow-left" size="xl" />
|
||||
</PluginLink>
|
||||
<Text.Title
|
||||
editable={false}
|
||||
|
|
|
|||
|
|
@ -35,3 +35,7 @@
|
|||
flex-grow: 1;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.button-back {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,33 +68,33 @@ exports[`PluginSetup there is an error message - retry setup 1`] = `
|
|||
class="configure-plugin"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1pq88ji-button"
|
||||
class="css-72lnkn-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Retry
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
class="css-1pq88ji-button"
|
||||
class="css-72lnkn-button"
|
||||
href="/plugins/grafana-oncall-app?page=configuration"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Configure Plugin
|
||||
</span>
|
||||
|
|
@ -124,33 +124,33 @@ exports[`PluginSetup there is an error message 1`] = `
|
|||
class="configure-plugin"
|
||||
>
|
||||
<div
|
||||
class="css-ve64a7-horizontal-group"
|
||||
class="css-ffyaiw-horizontal-group"
|
||||
style="width: 100%; height: 100%;"
|
||||
>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<button
|
||||
class="css-1pq88ji-button"
|
||||
class="css-72lnkn-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Retry
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="css-cvef6c-layoutChildrenWrapper"
|
||||
class="css-18qv8yz-layoutChildrenWrapper"
|
||||
>
|
||||
<a
|
||||
class="css-1pq88ji-button"
|
||||
class="css-72lnkn-button"
|
||||
href="/plugins/grafana-oncall-app?page=configuration"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="css-1mhnkuh"
|
||||
class="css-1riaxdn"
|
||||
>
|
||||
Configure Plugin
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { GlobalSettingStore } from 'models/global_setting/global_setting';
|
|||
import { GrafanaTeamStore } from 'models/grafana_team/grafana_team';
|
||||
import { HeartbeatStore } from 'models/heartbeat/heartbeat';
|
||||
import { LabelStore } from 'models/label/label';
|
||||
import { LoaderStore } from 'models/loader/loader';
|
||||
import { OrganizationStore } from 'models/organization/organization';
|
||||
import { OutgoingWebhookStore } from 'models/outgoing_webhook/outgoing_webhook';
|
||||
import { ResolutionNotesStore } from 'models/resolution_note/resolution_note';
|
||||
|
|
@ -105,6 +106,7 @@ export class RootBaseStore {
|
|||
globalSettingStore = new GlobalSettingStore(this);
|
||||
filtersStore = new FiltersStore(this);
|
||||
labelsStore = new LabelStore(this);
|
||||
loaderStore = LoaderStore;
|
||||
|
||||
// stores
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,5 @@ import { RootStore } from './index';
|
|||
|
||||
export function useStore(): RootStore {
|
||||
const { store } = React.useContext(MobXProviderContext);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,3 +54,5 @@ export enum PAGE {
|
|||
}
|
||||
|
||||
export const TEXT_ELLIPSIS_CLASS = 'overflow-child';
|
||||
|
||||
export const INCIDENT_HORIZONTAL_SCROLLING_STORAGE = 'isIncidentalTableHorizontalScrolling';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,32 @@
|
|||
import { LoaderStore } from 'models/loader/loader';
|
||||
import { openErrorNotification, openNotification, openWarningNotification } from 'utils';
|
||||
|
||||
export function AutoLoadingState(actionKey: string) {
|
||||
return function (_target: object, _key: string, descriptor: PropertyDescriptor) {
|
||||
const originalFunction = descriptor.value;
|
||||
descriptor.value = async function (...args: any) {
|
||||
LoaderStore.setLoadingAction(actionKey, true);
|
||||
try {
|
||||
await originalFunction.apply(this, args);
|
||||
} finally {
|
||||
LoaderStore.setLoadingAction(actionKey, false);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function WrapAutoLoadingState(callback: Function, actionKey: string): (...params: any[]) => Promise<void> {
|
||||
return async (...params) => {
|
||||
LoaderStore.setLoadingAction(actionKey, true);
|
||||
|
||||
try {
|
||||
await callback(...params);
|
||||
} finally {
|
||||
LoaderStore.setLoadingAction(actionKey, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
type GlobalNotificationConfig = {
|
||||
success?: string;
|
||||
failure?: string;
|
||||
|
|
|
|||
|
|
@ -91,3 +91,7 @@ export function getPaths(obj?: any, parentKey?: string): string[] {
|
|||
}
|
||||
return concat(result, parentKey || []);
|
||||
}
|
||||
|
||||
export function pluralize(word: string, count: number): string {
|
||||
return count === 1 ? word : `${word}s`;
|
||||
}
|
||||
|
|
|
|||
8
grafana-plugin/src/utils/types.ts
Normal file
8
grafana-plugin/src/utils/types.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { RenderedCell } from 'rc-table/lib/interface';
|
||||
|
||||
export interface TableColumn {
|
||||
width?: string | number;
|
||||
title: string;
|
||||
key: string;
|
||||
render: (value: any, record: any, index: number) => React.ReactNode | RenderedCell<any>;
|
||||
}
|
||||
|
|
@ -1382,6 +1382,37 @@
|
|||
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
|
||||
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
|
||||
|
||||
"@dnd-kit/accessibility@^3.0.0":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz#3ccbefdfca595b0a23a5dc57d3de96bc6935641c"
|
||||
integrity sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@dnd-kit/core@^6.0.8":
|
||||
version "6.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-6.0.8.tgz#040ae13fea9787ee078e5f0361f3b49b07f3f005"
|
||||
integrity sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==
|
||||
dependencies:
|
||||
"@dnd-kit/accessibility" "^3.0.0"
|
||||
"@dnd-kit/utilities" "^3.2.1"
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@dnd-kit/sortable@^7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-7.0.2.tgz#791d550872457f3f3c843e00d159b640f982011c"
|
||||
integrity sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==
|
||||
dependencies:
|
||||
"@dnd-kit/utilities" "^3.2.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@dnd-kit/utilities@^3.2.0", "@dnd-kit/utilities@^3.2.1":
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.1.tgz#53f9e2016fd2506ec49e404c289392cfff30332a"
|
||||
integrity sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@emotion/babel-plugin@^11.10.5":
|
||||
version "11.10.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c"
|
||||
|
|
@ -1721,6 +1752,37 @@
|
|||
uplot "1.6.24"
|
||||
xss "^1.0.14"
|
||||
|
||||
"@grafana/data@10.2.0":
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/data/-/data-10.2.0.tgz#116190f47f51f2eebd608bd5299d7ce278899bbe"
|
||||
integrity sha512-MPUmkokQY7AWbJKVundp9AtTZdk4HqZHUCNvM1TFkTACUW9rVCi5fmmjwJQFLfTJ9JL2fkls8Z6S1l9Hd9ViTw==
|
||||
dependencies:
|
||||
"@braintree/sanitize-url" "6.0.2"
|
||||
"@grafana/schema" "10.2.0"
|
||||
"@types/d3-interpolate" "^3.0.0"
|
||||
"@types/string-hash" "1.1.1"
|
||||
d3-interpolate "3.0.1"
|
||||
date-fns "2.30.0"
|
||||
dompurify "^2.4.3"
|
||||
eventemitter3 "5.0.1"
|
||||
fast_array_intersect "1.1.0"
|
||||
history "4.10.1"
|
||||
lodash "4.17.21"
|
||||
marked "5.1.1"
|
||||
marked-mangle "1.1.0"
|
||||
moment "2.29.4"
|
||||
moment-timezone "0.5.43"
|
||||
ol "7.4.0"
|
||||
papaparse "5.4.1"
|
||||
react-use "17.4.0"
|
||||
regenerator-runtime "0.13.11"
|
||||
rxjs "7.8.1"
|
||||
string-hash "^1.1.3"
|
||||
tinycolor2 "1.6.0"
|
||||
tslib "2.6.0"
|
||||
uplot "1.6.26"
|
||||
xss "^1.0.14"
|
||||
|
||||
"@grafana/data@9.3.0-beta1":
|
||||
version "9.3.0-beta1"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/data/-/data-9.3.0-beta1.tgz#0c1d8da18b8f9a5c7e77312a1b36daf394bfc596"
|
||||
|
|
@ -1747,33 +1809,6 @@
|
|||
uplot "1.6.22"
|
||||
xss "1.0.14"
|
||||
|
||||
"@grafana/data@9.4.7":
|
||||
version "9.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/data/-/data-9.4.7.tgz#8b4c15a5b52ec13908c006baf87416354ee8251a"
|
||||
integrity sha512-GnP91XSuTlRaT4crRh7OgC58rKsF/ANAZTFeHOYqVD7r47upTgnnnM46khSLhvA3MoKfNZflXOneaIjU4c5Hyw==
|
||||
dependencies:
|
||||
"@braintree/sanitize-url" "6.0.1"
|
||||
"@grafana/schema" "9.4.7"
|
||||
"@types/d3-interpolate" "^3.0.0"
|
||||
d3-interpolate "3.0.1"
|
||||
date-fns "2.29.3"
|
||||
eventemitter3 "4.0.7"
|
||||
fast_array_intersect "1.1.0"
|
||||
history "4.10.1"
|
||||
lodash "4.17.21"
|
||||
marked "4.2.0"
|
||||
moment "2.29.4"
|
||||
moment-timezone "0.5.38"
|
||||
ol "7.1.0"
|
||||
papaparse "5.3.2"
|
||||
react-use "17.4.0"
|
||||
regenerator-runtime "0.13.10"
|
||||
rxjs "7.5.7"
|
||||
tinycolor2 "1.4.2"
|
||||
tslib "2.4.1"
|
||||
uplot "1.6.24"
|
||||
xss "1.0.14"
|
||||
|
||||
"@grafana/data@9.5.2":
|
||||
version "9.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/data/-/data-9.5.2.tgz#983042208a61c3a321499da7837fdd2ecbe7a04c"
|
||||
|
|
@ -1837,6 +1872,15 @@
|
|||
tslib "2.6.0"
|
||||
typescript "4.8.4"
|
||||
|
||||
"@grafana/e2e-selectors@10.2.0":
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/e2e-selectors/-/e2e-selectors-10.2.0.tgz#12110b75376cfeeeeb33d8bb57fca2b4119febb7"
|
||||
integrity sha512-mrYz7xri7H7TiYpDXQHeMHKMDzx2a9kIM0OklXhN1ZsQQSeYrh0+87EizyWeL0T7/d0OorLR4nq8zxVyVni8Bg==
|
||||
dependencies:
|
||||
"@grafana/tsconfig" "^1.2.0-rc1"
|
||||
tslib "2.6.0"
|
||||
typescript "4.8.4"
|
||||
|
||||
"@grafana/e2e-selectors@9.3.0-beta1":
|
||||
version "9.3.0-beta1"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/e2e-selectors/-/e2e-selectors-9.3.0-beta1.tgz#49ca6a4957763a8fee8560a5cd7f546a3f4853d3"
|
||||
|
|
@ -1846,15 +1890,6 @@
|
|||
tslib "2.4.1"
|
||||
typescript "4.8.4"
|
||||
|
||||
"@grafana/e2e-selectors@9.4.7":
|
||||
version "9.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/e2e-selectors/-/e2e-selectors-9.4.7.tgz#7632bf927dc885ddeea0a865084badf93b2d777a"
|
||||
integrity sha512-HvLgA9gccMC1uPx5Q+858yPjkfD5O0Kekm0p/ufQn+BA8dFbPpqVVd5cnu+/J3duKKHOsGBvZIShIOKNzkYw8g==
|
||||
dependencies:
|
||||
"@grafana/tsconfig" "^1.2.0-rc1"
|
||||
tslib "2.4.1"
|
||||
typescript "4.8.4"
|
||||
|
||||
"@grafana/e2e-selectors@9.5.2":
|
||||
version "9.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/e2e-selectors/-/e2e-selectors-9.5.2.tgz#8d56e0c11d7dfb85e0b9a908397abb58cfbc2325"
|
||||
|
|
@ -1916,6 +1951,16 @@
|
|||
"@opentelemetry/otlp-transformer" "^0.41.2"
|
||||
murmurhash-js "^1.0.0"
|
||||
|
||||
"@grafana/faro-core@^1.2.1":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.2.3.tgz#03faae6ee93664cfda39dfd3059f42bbdb7aeae0"
|
||||
integrity sha512-y2cfow8JLMrvSC4/Pd64/hByoAw5MWOPHmvpAueWNL0Cohj0XOGbKllQjTjnmCnDuLjAARS0pKAVdyVPjw9s6Q==
|
||||
dependencies:
|
||||
"@opentelemetry/api" "^1.4.1"
|
||||
"@opentelemetry/api-metrics" "^0.33.0"
|
||||
"@opentelemetry/otlp-transformer" "^0.41.2"
|
||||
murmurhash-js "^1.0.0"
|
||||
|
||||
"@grafana/faro-web-sdk@1.0.0-beta2":
|
||||
version "1.0.0-beta2"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta2.tgz#d096a350d6366a108428a205753c797802eb480d"
|
||||
|
|
@ -1943,6 +1988,15 @@
|
|||
ua-parser-js "^1.0.32"
|
||||
web-vitals "^3.1.1"
|
||||
|
||||
"@grafana/faro-web-sdk@1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.2.1.tgz#4818884bba26f07ebe563084fc0e4eed4108ef8d"
|
||||
integrity sha512-86Bk3IjVNdV/WufkdPJVUvjx7PYKjPV5n2Szpn+dOewZqEDd1lIqhyFYqVVM9kdjT+ARbSzY5BZvb+r0Kh8tuQ==
|
||||
dependencies:
|
||||
"@grafana/faro-core" "^1.2.1"
|
||||
ua-parser-js "^1.0.32"
|
||||
web-vitals "^3.1.1"
|
||||
|
||||
"@grafana/faro-web-sdk@^1.0.0-beta4":
|
||||
version "1.0.0-beta4"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.0.0-beta4.tgz#de9ec9b1201b4f02e3746f31dc0e7a3f77df47b3"
|
||||
|
|
@ -1973,10 +2027,10 @@
|
|||
"@opentelemetry/sdk-trace-web" "^1.8.0"
|
||||
"@opentelemetry/semantic-conventions" "^1.8.0"
|
||||
|
||||
"@grafana/labels@1.3.4":
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/labels/-/labels-1.3.4.tgz#8d9cdd215a80a1da1045d402c037be85d7efd6f5"
|
||||
integrity sha512-YYCuLGvtrMz7KkbMc6qoNJQr6drDLo6mMI27LcqsTDMHCNO3uJWpzC1Q2Y9MIwctIuTFYhbgfLvIunEegCx6PQ==
|
||||
"@grafana/labels@~1.3.5":
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/labels/-/labels-1.3.5.tgz#c53b64e12a6360d7558dc9bc0fff8c6b31983acb"
|
||||
integrity sha512-e79Ef/Bg5mGx0Mx6qGB65+6Z8HUHwXE4V8rjpI8EalWjARu6JlF27YBH28vbRX0kl1jepZHOi9EwYyck9y73PA==
|
||||
dependencies:
|
||||
"@emotion/css" "^11.11.2"
|
||||
"@grafana/ui" "^10.0.0"
|
||||
|
|
@ -2008,6 +2062,13 @@
|
|||
dependencies:
|
||||
tslib "2.6.0"
|
||||
|
||||
"@grafana/schema@10.2.0":
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/schema/-/schema-10.2.0.tgz#4b21aed47cd521484c899ef26737b5e4cc2ea323"
|
||||
integrity sha512-IvjlezsOfIRjnsOwTJ1qu1GWbq9Rz3ofFi2Pd+1Brza6Gn951Hv/5MlLwqIuZJ+VnSVs35ZlNOl3sz9uSq2ibg==
|
||||
dependencies:
|
||||
tslib "2.6.0"
|
||||
|
||||
"@grafana/schema@9.2.4":
|
||||
version "9.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/schema/-/schema-9.2.4.tgz#d96bfa80ef0f5e59d83002544d4570c19d79b934"
|
||||
|
|
@ -2022,13 +2083,6 @@
|
|||
dependencies:
|
||||
tslib "2.4.1"
|
||||
|
||||
"@grafana/schema@9.4.7":
|
||||
version "9.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/schema/-/schema-9.4.7.tgz#bb918ec7f096e0b81d7ead921ac1addeb265dd0e"
|
||||
integrity sha512-uTrg/XmMhfxXTSRskNRdUzDCK9XdwHHnNJkfUltzSF5v16bc9iE1u/NrkuEBxoLh6hji9Gd6pw7mS0K9o9/0ww==
|
||||
dependencies:
|
||||
tslib "2.4.1"
|
||||
|
||||
"@grafana/schema@9.5.2":
|
||||
version "9.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/schema/-/schema-9.5.2.tgz#336587ceb9cb1391b3d07d9e0372a7812cb7b215"
|
||||
|
|
@ -2344,74 +2398,76 @@
|
|||
uplot "1.6.24"
|
||||
uuid "9.0.0"
|
||||
|
||||
"@grafana/ui@^9.4.7":
|
||||
version "9.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/ui/-/ui-9.4.7.tgz#19ed1b36db85013070da118f4d87f13abb38567c"
|
||||
integrity sha512-MnEXrGRh3t4LkShP/Q0bfzFooiE4xbDagQ/17/B1VIwMWECsYeSQsEYuA2p/9yjTpOiL2YfB72uyAThpGYpQew==
|
||||
"@grafana/ui@^10.2.0":
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/ui/-/ui-10.2.0.tgz#99920ee490d52c014b28d61ca0d9d86294a15f41"
|
||||
integrity sha512-RzvR053LVV8qYRrfFPMjzEeABwahVOeyQPXmU5vmYccPolQYXbc8wp149wjTf5xdUygqQunRADI6sAqgRpVrdA==
|
||||
dependencies:
|
||||
"@emotion/css" "11.10.5"
|
||||
"@emotion/react" "11.10.5"
|
||||
"@grafana/data" "9.4.7"
|
||||
"@grafana/e2e-selectors" "9.4.7"
|
||||
"@grafana/schema" "9.4.7"
|
||||
"@leeoniya/ufuzzy" "0.9.0"
|
||||
"@monaco-editor/react" "4.4.6"
|
||||
"@popperjs/core" "2.11.6"
|
||||
"@react-aria/button" "3.6.1"
|
||||
"@react-aria/dialog" "3.3.1"
|
||||
"@react-aria/focus" "3.8.0"
|
||||
"@react-aria/menu" "3.6.1"
|
||||
"@react-aria/overlays" "3.10.1"
|
||||
"@react-aria/utils" "3.13.1"
|
||||
"@react-stately/menu" "3.4.1"
|
||||
"@sentry/browser" "6.19.7"
|
||||
"@emotion/css" "11.11.2"
|
||||
"@emotion/react" "11.11.1"
|
||||
"@grafana/data" "10.2.0"
|
||||
"@grafana/e2e-selectors" "10.2.0"
|
||||
"@grafana/faro-web-sdk" "1.2.1"
|
||||
"@grafana/schema" "10.2.0"
|
||||
"@leeoniya/ufuzzy" "1.0.8"
|
||||
"@monaco-editor/react" "4.6.0"
|
||||
"@popperjs/core" "2.11.8"
|
||||
"@react-aria/button" "3.8.0"
|
||||
"@react-aria/dialog" "3.5.3"
|
||||
"@react-aria/focus" "3.13.0"
|
||||
"@react-aria/menu" "3.10.0"
|
||||
"@react-aria/overlays" "3.15.0"
|
||||
"@react-aria/utils" "3.18.0"
|
||||
"@react-stately/menu" "3.5.3"
|
||||
ansicolor "1.1.100"
|
||||
calculate-size "1.1.1"
|
||||
classnames "2.3.2"
|
||||
core-js "3.27.1"
|
||||
d3 "7.8.2"
|
||||
date-fns "2.29.3"
|
||||
core-js "3.33.0"
|
||||
d3 "7.8.5"
|
||||
date-fns "2.30.0"
|
||||
hoist-non-react-statics "3.3.2"
|
||||
i18next "^22.0.0"
|
||||
immutable "4.2.2"
|
||||
i18next-browser-languagedetector "^7.0.2"
|
||||
immutable "4.3.1"
|
||||
is-hotkey "0.2.0"
|
||||
jquery "3.6.1"
|
||||
jquery "3.7.0"
|
||||
lodash "4.17.21"
|
||||
memoize-one "6.0.0"
|
||||
micro-memoize "^4.1.2"
|
||||
moment "2.29.4"
|
||||
monaco-editor "0.34.0"
|
||||
ol "7.1.0"
|
||||
ol "7.4.0"
|
||||
prismjs "1.29.0"
|
||||
rc-cascader "3.8.0"
|
||||
rc-drawer "6.1.2"
|
||||
rc-slider "10.1.0"
|
||||
rc-cascader "3.18.1"
|
||||
rc-drawer "6.5.2"
|
||||
rc-slider "10.3.1"
|
||||
rc-time-picker "^3.7.3"
|
||||
rc-tooltip "5.3.1"
|
||||
rc-tooltip "6.0.1"
|
||||
react-beautiful-dnd "13.1.1"
|
||||
react-calendar "3.9.0"
|
||||
react-calendar "4.3.0"
|
||||
react-colorful "5.6.1"
|
||||
react-custom-scrollbars-2 "4.5.0"
|
||||
react-dropzone "14.2.3"
|
||||
react-highlight-words "0.20.0"
|
||||
react-hook-form "7.5.3"
|
||||
react-i18next "^12.0.0"
|
||||
react-inlinesvg "3.0.1"
|
||||
react-inlinesvg "3.0.2"
|
||||
react-loading-skeleton "3.3.1"
|
||||
react-popper "2.3.0"
|
||||
react-popper-tooltip "4.4.2"
|
||||
react-router-dom "^5.2.0"
|
||||
react-select "5.6.0"
|
||||
react-router-dom "5.3.3"
|
||||
react-select "5.7.4"
|
||||
react-select-event "^5.1.0"
|
||||
react-table "7.8.0"
|
||||
react-transition-group "4.4.5"
|
||||
react-use "17.4.0"
|
||||
react-window "1.8.8"
|
||||
rxjs "7.5.7"
|
||||
react-window "1.8.9"
|
||||
rxjs "7.8.1"
|
||||
slate "0.47.9"
|
||||
slate-plain-serializer "0.7.13"
|
||||
slate-react "0.22.10"
|
||||
tinycolor2 "1.4.2"
|
||||
tslib "2.4.1"
|
||||
uplot "1.6.24"
|
||||
tinycolor2 "1.6.0"
|
||||
tslib "2.6.0"
|
||||
uplot "1.6.26"
|
||||
uuid "9.0.0"
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.6":
|
||||
|
|
@ -2797,11 +2853,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@leeoniya/ufuzzy/-/ufuzzy-0.8.0.tgz#2ccfc29453e168ce5866bf6dee89771db404a7f7"
|
||||
integrity sha512-EOc0fEsIqe6CDZxC14efhybnPcXyJi7VaZby40mWASZD0CI78ONoF+4+LGlcT58jsAIwEims5ARbRqo+BVHEAQ==
|
||||
|
||||
"@leeoniya/ufuzzy@0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@leeoniya/ufuzzy/-/ufuzzy-0.9.0.tgz#efb8f19f64ef6ff754fc49935c9ad53ab99712c1"
|
||||
integrity sha512-p2zWsX0GwO1x723Yhb3KLAoSwp1geQvzRPHgIoOR/0qn8Ptpsb3b01+W47iAYR/NWo0pX36XQoTU0alVRykMAg==
|
||||
|
||||
"@leeoniya/ufuzzy@1.0.6":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@leeoniya/ufuzzy/-/ufuzzy-1.0.6.tgz#cbafcff1529d9592b92bd735f1e8b18f23eda983"
|
||||
|
|
@ -2848,7 +2899,7 @@
|
|||
dependencies:
|
||||
state-local "^1.0.6"
|
||||
|
||||
"@monaco-editor/loader@^1.3.3":
|
||||
"@monaco-editor/loader@^1.3.3", "@monaco-editor/loader@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.4.0.tgz#f08227057331ec890fa1e903912a5b711a2ad558"
|
||||
integrity sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==
|
||||
|
|
@ -2870,6 +2921,13 @@
|
|||
dependencies:
|
||||
"@monaco-editor/loader" "^1.3.3"
|
||||
|
||||
"@monaco-editor/react@4.6.0":
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.6.0.tgz#bcc68671e358a21c3814566b865a54b191e24119"
|
||||
integrity sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.4.0"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
|
|
@ -3230,6 +3288,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
|
||||
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
|
||||
|
||||
"@popperjs/core@2.11.8":
|
||||
version "2.11.8"
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||
|
||||
"@rc-component/portal@^1.0.0-6":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@rc-component/portal/-/portal-1.1.1.tgz#1a30ffe51c240b54360cba8e8bfc5d1f559325c4"
|
||||
|
|
@ -4539,12 +4602,12 @@
|
|||
"@types/history" "^4.7.11"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-test-renderer@^17.0.2":
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.2.tgz#5f800a39b12ac8d2a2149e7e1885215bcf4edbbf"
|
||||
integrity sha512-+F1KONQTBHDBBhbHuT2GNydeMpPuviduXIVJRB7Y4nma4NR5DrTJfMMZ+jbhEHbpwL+Uqhs1WXh4KHiyrtYTPg==
|
||||
"@types/react-test-renderer@^18.0.5":
|
||||
version "18.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-18.0.5.tgz#b67a6ff37acd93d1b971ec4c838f69d52e772db0"
|
||||
integrity sha512-PsnmF4Hpi61PTRX+dTxkjgDdtZ09kFFgPXczoF+yBfOVxn7xBLPvKP1BUrSasYHmerj33rhoJuvpIMsJuyRqHw==
|
||||
dependencies:
|
||||
"@types/react" "^17"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.5":
|
||||
version "4.4.5"
|
||||
|
|
@ -6290,11 +6353,6 @@ core-js@3.26.0:
|
|||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.0.tgz#a516db0ed0811be10eac5d94f3b8463d03faccfe"
|
||||
integrity sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==
|
||||
|
||||
core-js@3.27.1:
|
||||
version "3.27.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.1.tgz#23cc909b315a6bb4e418bf40a52758af2103ba46"
|
||||
integrity sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==
|
||||
|
||||
core-js@3.28.0:
|
||||
version "3.28.0"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.28.0.tgz#ed8b9e99c273879fdfff0edfc77ee709a5800e4a"
|
||||
|
|
@ -6305,6 +6363,11 @@ core-js@3.31.0:
|
|||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.31.0.tgz#4471dd33e366c79d8c0977ed2d940821719db344"
|
||||
integrity sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==
|
||||
|
||||
core-js@3.33.0:
|
||||
version "3.33.0"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.0.tgz#70366dbf737134761edb017990cf5ce6c6369c40"
|
||||
integrity sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==
|
||||
|
||||
core-js@^2.4.0:
|
||||
version "2.6.12"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
||||
|
|
@ -8012,6 +8075,11 @@ eventemitter3@5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.0.tgz#084eb7f5b5388df1451e63f4c2aafd71b217ccb3"
|
||||
integrity sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg==
|
||||
|
||||
eventemitter3@5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
|
||||
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
|
||||
|
||||
events@^3.2.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
|
||||
|
|
@ -9085,16 +9153,16 @@ immer@^9.0.7:
|
|||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.16.tgz#8e7caab80118c2b54b37ad43e05758cdefad0198"
|
||||
integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==
|
||||
|
||||
immutability-helper@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.1.1.tgz#2b86b2286ed3b1241c9e23b7b21e0444f52f77b7"
|
||||
integrity sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==
|
||||
|
||||
immutable@4.1.0, immutable@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef"
|
||||
integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==
|
||||
|
||||
immutable@4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.2.tgz#2da9ff4384a4330c36d4d1bc88e90f9e0b0ccd16"
|
||||
integrity sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==
|
||||
|
||||
immutable@4.2.4:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.4.tgz#83260d50889526b4b531a5e293709a77f7c55a2a"
|
||||
|
|
@ -9105,6 +9173,11 @@ immutable@4.3.0:
|
|||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be"
|
||||
integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==
|
||||
|
||||
immutable@4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.1.tgz#17988b356097ab0719e2f741d56f3ec6c317f9dc"
|
||||
integrity sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A==
|
||||
|
||||
import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
|
|
@ -10888,6 +10961,11 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1:
|
|||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
micro-memoize@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/micro-memoize/-/micro-memoize-4.1.2.tgz#ce719c1ba1e41592f1cd91c64c5f41dcbf135f36"
|
||||
integrity sha512-+HzcV2H+rbSJzApgkj0NdTakkC+bnyeiUxgT6/m7mjcz1CmM22KYFKp+EVj1sWe4UYcnriJr5uqHQD/gMHLD+g==
|
||||
|
||||
micromark@~2.11.0:
|
||||
version "2.11.4"
|
||||
resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a"
|
||||
|
|
@ -11061,6 +11139,13 @@ moment-timezone@0.5.41:
|
|||
dependencies:
|
||||
moment "^2.29.4"
|
||||
|
||||
moment-timezone@0.5.43:
|
||||
version "0.5.43"
|
||||
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.43.tgz#3dd7f3d0c67f78c23cd1906b9b2137a09b3c4790"
|
||||
integrity sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==
|
||||
dependencies:
|
||||
moment "^2.29.4"
|
||||
|
||||
moment@2.29.4, moment@2.x, "moment@>= 2.9.0", moment@^2.29.4:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
|
|
@ -12752,6 +12837,18 @@ rc-cascader@3.12.1:
|
|||
rc-tree "~5.7.0"
|
||||
rc-util "^5.6.1"
|
||||
|
||||
rc-cascader@3.18.1:
|
||||
version "3.18.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.18.1.tgz#e488e9cd9ace1617e06ee4c8eadf435a11de2d29"
|
||||
integrity sha512-M7Xr5Fs/E87ZGustfObtBYQjsvBCET0UX2JYXB2GmOP+2fsZgjaRGXK+CJBmmWXQ6o4OFinpBQBXG4wJOQ5MEg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
array-tree-filter "^2.1.0"
|
||||
classnames "^2.3.1"
|
||||
rc-select "~14.9.0"
|
||||
rc-tree "~5.7.0"
|
||||
rc-util "^5.35.0"
|
||||
|
||||
rc-cascader@3.7.0:
|
||||
version "3.7.0"
|
||||
resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.7.0.tgz#98134df578ce1cca22be8fb4319b04df4f3dca36"
|
||||
|
|
@ -12785,17 +12882,6 @@ rc-drawer@4.4.3:
|
|||
classnames "^2.2.6"
|
||||
rc-util "^5.7.0"
|
||||
|
||||
rc-drawer@6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-6.1.2.tgz#032918a21bfa8a7d9e52ada1e7b8ed08c0ae6346"
|
||||
integrity sha512-mYsTVT8Amy0LRrpVEv7gI1hOjtfMSO/qHAaCDzFx9QBLnms3cAQLJkaxRWM+Eq99oyLhU/JkgoqTg13bc4ogOQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
"@rc-component/portal" "^1.0.0-6"
|
||||
classnames "^2.2.6"
|
||||
rc-motion "^2.6.1"
|
||||
rc-util "^5.21.2"
|
||||
|
||||
rc-drawer@6.1.3:
|
||||
version "6.1.3"
|
||||
resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-6.1.3.tgz#4b2277db09f059be7144dc82d5afede9c2ab2191"
|
||||
|
|
@ -12818,6 +12904,17 @@ rc-drawer@6.3.0:
|
|||
rc-motion "^2.6.1"
|
||||
rc-util "^5.21.2"
|
||||
|
||||
rc-drawer@6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-6.5.2.tgz#49c1f279261992f6d4653d32a03b14acd436d610"
|
||||
integrity sha512-QckxAnQNdhh4vtmKN0ZwDf3iakO83W9eZcSKWYYTDv4qcD2fHhRAZJJ/OE6v2ZlQ2kSqCJX5gYssF4HJFvsEPQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
"@rc-component/portal" "^1.1.1"
|
||||
classnames "^2.2.6"
|
||||
rc-motion "^2.6.1"
|
||||
rc-util "^5.36.0"
|
||||
|
||||
rc-motion@^2.0.0, rc-motion@^2.0.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.6.2.tgz#3d31f97e41fb8e4f91a4a4189b6a98ac63342869"
|
||||
|
|
@ -12846,6 +12943,16 @@ rc-overflow@^1.0.0:
|
|||
rc-resize-observer "^1.0.0"
|
||||
rc-util "^5.19.2"
|
||||
|
||||
rc-overflow@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.3.2.tgz#72ee49e85a1308d8d4e3bd53285dc1f3e0bcce2c"
|
||||
integrity sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.11.1"
|
||||
classnames "^2.2.1"
|
||||
rc-resize-observer "^1.0.0"
|
||||
rc-util "^5.37.0"
|
||||
|
||||
rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz#9f46052f81cdf03498be35144cb7c53fd282c4c7"
|
||||
|
|
@ -12905,6 +13012,19 @@ rc-select@~14.5.0:
|
|||
rc-util "^5.16.1"
|
||||
rc-virtual-list "^3.5.2"
|
||||
|
||||
rc-select@~14.9.0:
|
||||
version "14.9.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.9.2.tgz#24c4673e21b1d5a4a126b9a934609cce5c39d1a5"
|
||||
integrity sha512-VQ15sRFgPURHb8ZcZNSDtb2rAw3+C9xlL0nDziwNHTEW1KvEpZ8y+0v5w24X/Bpl9b3cW1BOyW1F5UqSAq+7Dg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
"@rc-component/trigger" "^1.5.0"
|
||||
classnames "2.x"
|
||||
rc-motion "^2.0.1"
|
||||
rc-overflow "^1.3.1"
|
||||
rc-util "^5.16.1"
|
||||
rc-virtual-list "^3.5.2"
|
||||
|
||||
rc-slider@10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.0.1.tgz#7058c68ff1e1aa4e7c3536e5e10128bdbccb87f9"
|
||||
|
|
@ -12915,16 +13035,6 @@ rc-slider@10.0.1:
|
|||
rc-util "^5.18.1"
|
||||
shallowequal "^1.1.0"
|
||||
|
||||
rc-slider@10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.1.0.tgz#11e401d8412ae20f9c2ee478bdbaddd042158753"
|
||||
integrity sha512-nhC8V0+lNj4gGKZix2QAfcj/EP3NvCtFhNJPFMvXUdn7pe8bSa2vXNSxQVN5b9veVSic4Xeqgd/7KamX3gqznA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
classnames "^2.2.5"
|
||||
rc-util "^5.18.1"
|
||||
shallowequal "^1.1.0"
|
||||
|
||||
rc-slider@10.1.1:
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.1.1.tgz#5e82036e60b61021aba3ea0e353744dd7c74e104"
|
||||
|
|
@ -12943,6 +13053,15 @@ rc-slider@10.2.1:
|
|||
classnames "^2.2.5"
|
||||
rc-util "^5.27.0"
|
||||
|
||||
rc-slider@10.3.1:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.3.1.tgz#345e818975f4bb61b66340799af8cfccad7c8ad7"
|
||||
integrity sha512-XszsZLkbjcG9ogQy/zUC0n2kndoKUAnY/Vnk1Go5Gx+JJQBz0Tl15d5IfSiglwBUZPS9vsUJZkfCmkIZSqWbcA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
classnames "^2.2.5"
|
||||
rc-util "^5.27.0"
|
||||
|
||||
rc-table@^7.17.1:
|
||||
version "7.28.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.28.1.tgz#a1116653e8ccd3ddd69379694da41c3ee9ced9ed"
|
||||
|
|
@ -13083,6 +13202,14 @@ rc-util@^5.33.0, rc-util@^5.36.0:
|
|||
"@babel/runtime" "^7.18.3"
|
||||
react-is "^16.12.0"
|
||||
|
||||
rc-util@^5.35.0, rc-util@^5.37.0:
|
||||
version "5.38.0"
|
||||
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.38.0.tgz#18a3d1c26ba3c43fabfbe6303e825dabd9e5f4f0"
|
||||
integrity sha512-yV/YBNdFn+edyBpBdCqkPE29Su0jWcHNgwx2dJbRqMrMfrUcMJUjCRV+ZPhcvWyKFJ63GzEerPrz9JIVo0zXmA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.18.3"
|
||||
react-is "^18.2.0"
|
||||
|
||||
rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.8:
|
||||
version "3.4.11"
|
||||
resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.4.11.tgz#97f5e947380d546a2ca8ad229d8e41e9b33b20c6"
|
||||
|
|
@ -13209,16 +13336,7 @@ react-dev-utils@^12.0.0:
|
|||
strip-ansi "^6.0.1"
|
||||
text-table "^0.2.0"
|
||||
|
||||
react-dom@17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
scheduler "^0.20.2"
|
||||
|
||||
react-dom@^18.0.0:
|
||||
react-dom@18.2.0, react-dom@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
|
||||
|
|
@ -13328,7 +13446,7 @@ react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
|
|||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0:
|
||||
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
|
@ -13491,7 +13609,22 @@ react-select@5.7.0:
|
|||
react-transition-group "^4.3.0"
|
||||
use-isomorphic-layout-effect "^1.1.2"
|
||||
|
||||
react-shallow-renderer@^16.13.1:
|
||||
react-select@5.7.4:
|
||||
version "5.7.4"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.4.tgz#d8cad96e7bc9d6c8e2709bdda8f4363c5dd7ea7d"
|
||||
integrity sha512-NhuE56X+p9QDFh4BgeygHFIvJJszO1i1KSkg/JPcIJrbovyRtI+GuOEa4XzFCEpZRAEoEI8u/cAHK+jG/PgUzQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.0"
|
||||
"@emotion/cache" "^11.4.0"
|
||||
"@emotion/react" "^11.8.1"
|
||||
"@floating-ui/dom" "^1.0.1"
|
||||
"@types/react-transition-group" "^4.4.0"
|
||||
memoize-one "^6.0.0"
|
||||
prop-types "^15.6.0"
|
||||
react-transition-group "^4.3.0"
|
||||
use-isomorphic-layout-effect "^1.1.2"
|
||||
|
||||
react-shallow-renderer@^16.15.0:
|
||||
version "16.15.0"
|
||||
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457"
|
||||
integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==
|
||||
|
|
@ -13520,15 +13653,14 @@ react-table@7.8.0:
|
|||
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2"
|
||||
integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==
|
||||
|
||||
react-test-renderer@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c"
|
||||
integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==
|
||||
react-test-renderer@^18.0.2:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-18.2.0.tgz#1dd912bd908ff26da5b9fca4fd1c489b9523d37e"
|
||||
integrity sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==
|
||||
dependencies:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^17.0.2"
|
||||
react-shallow-renderer "^16.13.1"
|
||||
scheduler "^0.20.2"
|
||||
react-is "^18.2.0"
|
||||
react-shallow-renderer "^16.15.0"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-transition-group@4.4.5, react-transition-group@^4.3.0, react-transition-group@^4.4.5:
|
||||
version "4.4.5"
|
||||
|
|
@ -13573,15 +13705,15 @@ react-window@1.8.8:
|
|||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
react@17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
|
||||
react-window@1.8.9:
|
||||
version "1.8.9"
|
||||
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.9.tgz#24bc346be73d0468cdf91998aac94e32bc7fa6a8"
|
||||
integrity sha512-+Eqx/fj1Aa5WnhRfj9dJg4VYATGwIUP2ItwItiJ6zboKWA6EX3lYDAXfGF2hyNqplEprhbtjbipiADEcwQ823Q==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
react@^18.0.0:
|
||||
react@18.2.0, react@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||
|
|
@ -13978,6 +14110,13 @@ rxjs@7.8.0:
|
|||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
rxjs@7.8.1:
|
||||
version "7.8.1"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
|
||||
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
rxjs@^6.4.0, rxjs@^6.6.0:
|
||||
version "6.6.7"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
|
||||
|
|
@ -14048,14 +14187,6 @@ saxes@^5.0.1:
|
|||
dependencies:
|
||||
xmlchars "^2.2.0"
|
||||
|
||||
scheduler@^0.20.2:
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
|
||||
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
scheduler@^0.23.0:
|
||||
version "0.23.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
|
||||
|
|
@ -15268,6 +15399,11 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
|||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||
|
|
@ -15476,6 +15612,11 @@ uplot@1.6.24:
|
|||
resolved "https://registry.yarnpkg.com/uplot/-/uplot-1.6.24.tgz#dfa213fa7da92763261920ea972ed1a5f9f6af12"
|
||||
integrity sha512-WpH2BsrFrqxkMu+4XBvc0eCDsRBhzoq9crttYeSI0bfxpzR5YoSVzZXOKFVWcVC7sp/aDXrdDPbDZGCtck2PVg==
|
||||
|
||||
uplot@1.6.26:
|
||||
version "1.6.26"
|
||||
resolved "https://registry.yarnpkg.com/uplot/-/uplot-1.6.26.tgz#a6012fd141ad4a71741c75af0c71283d0ade45a7"
|
||||
integrity sha512-qN0mveL6UsP40TnHzHAJkUQvpfA3y8zSLXtXKVlJo/sLfj2+vjan/Z3g81MCZjy/hEDUFNtnLftPmETDA4s7Rg==
|
||||
|
||||
upper-case-first@^1.1.0, upper-case-first@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue