commit
64913ac47e
243 changed files with 597 additions and 483 deletions
41
README.md
41
README.md
|
|
@ -28,6 +28,11 @@ Developer-friendly incident response with brilliant Slack integration.
|
|||
|
||||
## Getting Started
|
||||
|
||||
> [!IMPORTANT]
|
||||
> These instructions are for using Grafana 11 or newer. You must enable the feature toggle for
|
||||
> `externalServiceAccounts`. This is already done for the docker files and helm charts. If you are running Grafana
|
||||
> separately see the Grafana documentation on how to enable this.
|
||||
|
||||
We prepared multiple environments:
|
||||
|
||||
- [production](https://grafana.com/docs/oncall/latest/open-source/#production-environment)
|
||||
|
|
@ -82,17 +87,41 @@ We prepared multiple environments:
|
|||
docker-compose pull && docker-compose up -d
|
||||
```
|
||||
|
||||
5. Go to [OnCall Plugin Configuration](http://localhost:3000/plugins/grafana-oncall-app), using log in credentials
|
||||
as defined above: `admin`/`admin` (or find OnCall plugin in configuration->plugins) and connect OnCall _plugin_
|
||||
with OnCall _backend_:
|
||||
5. Provision the plugin (If you run Grafana outside the included docker files install the plugin before these steps):
|
||||
|
||||
```text
|
||||
OnCall backend URL: http://engine:8080
|
||||
If you are using the included docker compose file use `admin`/`admin` credentials and `localhost:3000` to
|
||||
perform this task. If you have configured Grafana differently adjust your credentials and hostnames accordingly.
|
||||
|
||||
```bash
|
||||
# Note: onCallApiUrl 'engine' and grafanaUrl 'grafana' use the name from the docker compose file. If you are
|
||||
# running your grafana or oncall engine instance with another hostname adjust accordingly.
|
||||
curl -X POST 'http://admin:admin@localhost:3000/api/plugins/grafana-oncall-app/settings' -H "Content-Type: application/json" -d '{"enabled":true, "jsonData":{"stackId":5, "orgId":100, "onCallApiUrl":"http://engine:8080", "grafanaUrl":"http://grafana:3000"}}'
|
||||
curl -X POST 'http://admin:admin@localhost:3000/api/plugins/grafana-oncall-app/resources/plugin/install'
|
||||
```
|
||||
|
||||
6. Enjoy! Check our [OSS docs](https://grafana.com/docs/oncall/latest/open-source/) if you want to set up
|
||||
6. Start using OnCall, log in to Grafana with credentials
|
||||
as defined above: `admin`/`admin`
|
||||
|
||||
7. Enjoy! Check our [OSS docs](https://grafana.com/docs/oncall/latest/open-source/) if you want to set up
|
||||
Slack, Telegram, Twilio or SMS/calls through Grafana Cloud.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Here are some API calls that can be made to help if you are having difficulty connecting Grafana and OnCall.
|
||||
(Modify parameters to match your credentials and environment)
|
||||
|
||||
```bash
|
||||
# Use this to get more information about the connection between Grafana and OnCall
|
||||
curl -X GET 'http://admin:admin@localhost:3000/api/plugins/grafana-oncall-app/resources/plugin/status'
|
||||
```
|
||||
|
||||
```bash
|
||||
# If you added a user or changed permissions and don't see it show up in OnCall you can manually trigger sync.
|
||||
# Note: This is called automatically when the app is loaded (page load/refresh) but there is a 5 min timeout so
|
||||
# that it does not generate unnecessary activity.
|
||||
curl -X POST 'http://admin:admin@localhost:3000/api/plugins/grafana-oncall-app/resources/plugin/sync'
|
||||
```
|
||||
|
||||
## Update version
|
||||
|
||||
To update your Grafana OnCall hobby environment:
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ services:
|
|||
GF_DATABASE_HOST: ${MYSQL_HOST:-mysql}
|
||||
GF_DATABASE_USER: ${MYSQL_USER:-root}
|
||||
GF_DATABASE_PASSWORD: ${MYSQL_PASSWORD:?err}
|
||||
GF_FEATURE_TOGGLES_ENABLE: externalServiceAccounts
|
||||
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
|
||||
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
|
||||
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ services:
|
|||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
GF_FEATURE_TOGGLES_ENABLE: externalServiceAccounts
|
||||
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
|
||||
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
|
||||
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class ApiTokenAuthentication(BaseAuthentication):
|
|||
auth = get_authorization_header(request).decode("utf-8")
|
||||
user, auth_token = self.authenticate_credentials(auth)
|
||||
|
||||
if not user_is_authorized(user, [RBACPermission.Permissions.API_KEYS_WRITE]):
|
||||
if not user.is_active or not user_is_authorized(user, [RBACPermission.Permissions.API_KEYS_WRITE]):
|
||||
raise exceptions.AuthenticationFailed(
|
||||
"Only users with Admin permissions are allowed to perform this action."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,26 @@ def test_plugin_authentication_fail(authorization, instance_context):
|
|||
PluginAuthentication().authenticate(request)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_plugin_authentication_inactive_user(make_organization, make_user, make_token_for_organization):
|
||||
organization = make_organization(stack_id=42, org_id=24)
|
||||
token, token_string = make_token_for_organization(organization)
|
||||
user = make_user(organization=organization, user_id=12)
|
||||
# user is set to inactive if deleted via queryset (ie. during sync)
|
||||
user.is_active = False
|
||||
user.save()
|
||||
|
||||
headers = {
|
||||
"HTTP_AUTHORIZATION": token_string,
|
||||
"HTTP_X-Instance-Context": INSTANCE_CONTEXT,
|
||||
"HTTP_X-Grafana-Context": '{"UserId": 12}',
|
||||
}
|
||||
request = APIRequestFactory().get("/", **headers)
|
||||
|
||||
with pytest.raises(AuthenticationFailed):
|
||||
PluginAuthentication().authenticate(request)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_plugin_authentication_gcom_setup_new_user(make_organization):
|
||||
# Setting gcom_token_org_last_time_synced to now, so it doesn't try to sync with gcom
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class MobileAppAuthTokenAuthentication(BaseAuthentication):
|
|||
def authenticate(self, request) -> Optional[Tuple[User, MobileAppAuthToken]]:
|
||||
auth = get_authorization_header(request).decode("utf-8")
|
||||
user, auth_token = self.authenticate_credentials(auth)
|
||||
if user is None:
|
||||
if user is None or not user.is_active:
|
||||
return None
|
||||
return user, auth_token
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from rest_framework import status
|
|||
from rest_framework.test import APIClient
|
||||
|
||||
from apps.mobile_app.models import MobileAppAuthToken
|
||||
from apps.user_management.models import User
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
@ -76,3 +77,17 @@ def test_mobile_app_auth_token(
|
|||
|
||||
response = client.get(url, HTTP_AUTHORIZATION=verification_token)
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_mobile_app_auth_token_deleted_user(
|
||||
make_organization_and_user_with_mobile_app_auth_token,
|
||||
):
|
||||
_, user, auth_token = make_organization_and_user_with_mobile_app_auth_token()
|
||||
# user is deleted via queryset (ie. setting it to inactive, during sync)
|
||||
User.objects.filter(id=user.id).delete()
|
||||
|
||||
client = APIClient()
|
||||
url = reverse("api-internal:alertgroup-list")
|
||||
response = client.get(url, HTTP_AUTHORIZATION=auth_token)
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
|
|
|||
|
|
@ -180,6 +180,20 @@ def test_get_alert_groups(alert_group_public_api_setup):
|
|||
assert response.json() == expected_response
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_alert_groups_inactive_user(make_organization_and_user_with_token):
|
||||
_, user, token = make_organization_and_user_with_token()
|
||||
# user is set to inactive if deleted via queryset (ie. during sync)
|
||||
user.is_active = False
|
||||
user.save()
|
||||
|
||||
client = APIClient()
|
||||
url = reverse("api-public:alert_groups-list")
|
||||
response = client.get(url, format="json", HTTP_AUTHORIZATION=token)
|
||||
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_alert_groups_include_labels(alert_group_public_api_setup, make_alert_group_label_association):
|
||||
token, _, _, _ = alert_group_public_api_setup
|
||||
|
|
|
|||
|
|
@ -4,19 +4,14 @@
|
|||
[run]
|
||||
init_cmds = [
|
||||
["mage", "-v", "build:debug"],
|
||||
["mage", "-v" , "reloadPlugin"],
|
||||
]
|
||||
watch_all = true
|
||||
follow_symlinks = false
|
||||
ignore = [".git", "node_modules", "dist"]
|
||||
ignore_files = ["mage_output_file.go"]
|
||||
watch_dirs = [
|
||||
"pkg",
|
||||
# "src",
|
||||
]
|
||||
watch_dirs = ["pkg"]
|
||||
watch_exts = [".go", ".json"]
|
||||
build_delay = 2000
|
||||
cmds = [
|
||||
["mage", "-v", "build:debug"],
|
||||
["mage", "-v" , "reloadPlugin"],
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { PLUGIN_CONFIG } from 'utils/consts';
|
||||
import { PLUGIN_CONFIG } from 'helpers/consts';
|
||||
|
||||
import { test, expect } from '../fixtures';
|
||||
import { goToGrafanaPage } from '../utils/navigation';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { waitInMs } from 'utils/async';
|
||||
import { waitInMs } from 'helpers/async';
|
||||
|
||||
import { test, expect, Page } from '../fixtures';
|
||||
import { OrgRole, isGrafanaVersionLowerThan } from '../utils/constants';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { HTML_ID } from 'helpers/DOM';
|
||||
|
||||
import { scheduleViewToDaysInOneRow } from 'models/schedule/schedule.helpers';
|
||||
import { ScheduleView } from 'models/schedule/schedule.types';
|
||||
import { HTML_ID } from 'utils/DOM';
|
||||
|
||||
import { expect, Page, test } from '../fixtures';
|
||||
import { isGrafanaVersionLowerThan } from '../utils/constants';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { KeyValue } from '@grafana/data';
|
||||
import type { Page } from '@playwright/test';
|
||||
import { getPluginId } from 'helpers/consts';
|
||||
import qs from 'query-string';
|
||||
|
||||
import { getPluginId } from 'utils/consts';
|
||||
|
||||
import { BASE_URL } from './constants';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
module github.com/grafana-labs/grafana-oncall-app
|
||||
module github.com/grafana/grafana-oncall-app
|
||||
|
||||
go 1.21.5
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package main
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/grafana-labs/grafana-oncall-app/pkg/plugin"
|
||||
"github.com/grafana/grafana-oncall-app/pkg/plugin"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/app"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
)
|
||||
|
|
@ -16,7 +16,7 @@ func main() {
|
|||
// argument. This factory will be automatically called on incoming request
|
||||
// from Grafana to create different instances of `App` (per plugin
|
||||
// ID).
|
||||
if err := app.Manage("grafana-oncall-app", plugin.NewApp, app.ManageOpts{}); err != nil {
|
||||
if err := app.Manage("grafana-oncall-app", plugin.NewInstance, app.ManageOpts{}); err != nil {
|
||||
log.DefaultLogger.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,15 +38,9 @@ type App struct {
|
|||
}
|
||||
|
||||
// NewApp creates a new example *App instance.
|
||||
func NewApp(ctx context.Context, settings backend.AppInstanceSettings) (instancemgmt.Instance, error) {
|
||||
func NewApp(ctx context.Context, settings backend.AppInstanceSettings) (*App, error) {
|
||||
var app App
|
||||
|
||||
// Use a httpadapter (provided by the SDK) for resource calls. This allows us
|
||||
// to use a *http.ServeMux for resource calls, so we can map multiple routes
|
||||
// to CallResource without having to implement extra logic.
|
||||
mux := http.NewServeMux()
|
||||
app.registerRoutes(mux)
|
||||
app.CallResourceHandler = httpadapter.New(mux)
|
||||
app.OnCallSyncCache = &OnCallSyncCache{}
|
||||
app.OnCallSettingsCache = &OnCallSettingsCache{}
|
||||
app.OnCallUserCache = NewOnCallUserCache()
|
||||
|
|
@ -66,6 +60,25 @@ func NewApp(ctx context.Context, settings backend.AppInstanceSettings) (instance
|
|||
return &app, nil
|
||||
}
|
||||
|
||||
// NewInstance creates a new example *Instance instance.
|
||||
func NewInstance(ctx context.Context, settings backend.AppInstanceSettings) (instancemgmt.Instance, error) {
|
||||
app, err := NewApp(ctx, settings)
|
||||
|
||||
if err != nil {
|
||||
log.DefaultLogger.Error("Error creating new app", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Use a httpadapter (provided by the SDK) for resource calls. This allows us
|
||||
// to use a *http.ServeMux for resource calls, so we can map multiple routes
|
||||
// to CallResource without having to implement extra logic.
|
||||
mux := http.NewServeMux()
|
||||
app.registerRoutes(mux)
|
||||
app.CallResourceHandler = httpadapter.New(mux)
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance
|
||||
// created.
|
||||
func (a *App) Dispose() {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package plugin
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type OnCallDebugStats struct {
|
||||
|
|
@ -47,7 +48,7 @@ func (a *App) handleDebugSync(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
onCallSync, err := a.GetSyncData(req.Context(), onCallPluginSettings)
|
||||
onCallSync, err := a.GetSyncData(onCallPluginSettings)
|
||||
if err != nil {
|
||||
log.DefaultLogger.Error("Error getting sync data", "error", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ func (a *App) handleInstall(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
onCallSync, err := a.GetSyncData(req.Context(), onCallPluginSettings)
|
||||
onCallSync, err := a.GetSyncData(onCallPluginSettings)
|
||||
if err != nil {
|
||||
log.DefaultLogger.Error("Error getting sync data", "error", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func afterRequest(handler http.Handler, afterFunc func(*responseWriter, *http.Re
|
|||
})
|
||||
}
|
||||
|
||||
func (a *App) handleInternalApi(w http.ResponseWriter, req *http.Request) {
|
||||
func (a *App) HandleInternalApi(w http.ResponseWriter, req *http.Request) {
|
||||
a.ProxyRequestToOnCall(w, req, "api/internal/v1/")
|
||||
}
|
||||
|
||||
|
|
@ -121,10 +121,10 @@ func (a *App) handleLegacyInstall(w *responseWriter, req *http.Request) {
|
|||
// registerRoutes takes a *http.ServeMux and registers some HTTP handlers.
|
||||
func (a *App) registerRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/plugin/install", a.handleInstall)
|
||||
mux.HandleFunc("/plugin/status", a.handleStatus)
|
||||
mux.HandleFunc("/plugin/sync", a.handleSync)
|
||||
mux.HandleFunc("/plugin/status", a.HandleStatus)
|
||||
mux.HandleFunc("/plugin/sync", a.HandleSync)
|
||||
|
||||
mux.Handle("/plugin/self-hosted/install", afterRequest(http.HandlerFunc(a.handleInternalApi), a.handleLegacyInstall))
|
||||
mux.Handle("/plugin/self-hosted/install", afterRequest(http.HandlerFunc(a.HandleInternalApi), a.handleLegacyInstall))
|
||||
|
||||
// Disable debug endpoints
|
||||
//mux.HandleFunc("/debug/user", a.handleDebugUser)
|
||||
|
|
@ -134,5 +134,5 @@ func (a *App) registerRoutes(mux *http.ServeMux) {
|
|||
//mux.HandleFunc("/debug/stats", a.handleDebugStats)
|
||||
//mux.HandleFunc("/debug/unlock", a.handleDebugUnlock)
|
||||
|
||||
mux.HandleFunc("/", a.handleInternalApi)
|
||||
mux.HandleFunc("/", a.HandleInternalApi)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ package plugin
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
)
|
||||
|
||||
// mockCallResourceResponseSender implements backend.CallResourceResponseSender
|
||||
|
|
@ -23,7 +24,7 @@ func (s *mockCallResourceResponseSender) Send(response *backend.CallResourceResp
|
|||
// This ensures the httpadapter for CallResource works correctly.
|
||||
func TestCallResource(t *testing.T) {
|
||||
// Initialize app
|
||||
inst, err := NewApp(context.Background(), backend.AppInstanceSettings{})
|
||||
inst, err := NewInstance(context.Background(), backend.AppInstanceSettings{})
|
||||
if err != nil {
|
||||
t.Fatalf("new app: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,32 +317,29 @@ func (a *App) SaveOnCallSettings(settings *OnCallPluginSettings) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *App) GetSyncData(ctx context.Context, settings *OnCallPluginSettings) (*OnCallSync, error) {
|
||||
func (a *App) GetSyncData(pluginSettings *OnCallPluginSettings) (*OnCallSync, error) {
|
||||
var err error
|
||||
|
||||
startGetSyncData := time.Now()
|
||||
defer func() {
|
||||
elapsed := time.Since(startGetSyncData)
|
||||
log.DefaultLogger.Info("GetSyncData", "time", elapsed.Milliseconds())
|
||||
}()
|
||||
|
||||
onCallPluginSettings, err := a.OnCallSettingsFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting settings from context = %v", err)
|
||||
}
|
||||
|
||||
onCallSync := OnCallSync{
|
||||
Settings: *settings,
|
||||
Settings: *pluginSettings,
|
||||
}
|
||||
onCallSync.Users, err = a.GetAllUsersWithPermissions(onCallPluginSettings)
|
||||
onCallSync.Users, err = a.GetAllUsersWithPermissions(pluginSettings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting users = %v", err)
|
||||
}
|
||||
|
||||
onCallSync.Teams, err = a.GetAllTeams(onCallPluginSettings)
|
||||
onCallSync.Teams, err = a.GetAllTeams(pluginSettings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting teams = %v", err)
|
||||
}
|
||||
|
||||
teamMembers, err := a.GetAllTeamMembers(onCallPluginSettings, onCallSync.Teams)
|
||||
teamMembers, err := a.GetAllTeamMembers(pluginSettings, onCallSync.Teams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting team members = %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ func (a *App) ValidateOnCallStatus(ctx context.Context, settings *OnCallPluginSe
|
|||
return &status, nil
|
||||
}
|
||||
|
||||
func (a *App) handleStatus(w http.ResponseWriter, req *http.Request) {
|
||||
func (a *App) HandleStatus(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
)
|
||||
|
||||
type OnCallSyncCache struct {
|
||||
|
|
@ -38,7 +39,7 @@ func (oc *OnCallSyncCache) UnlockAfterDelay(delay time.Duration) {
|
|||
})
|
||||
}
|
||||
|
||||
func (a *App) handleSync(w http.ResponseWriter, req *http.Request) {
|
||||
func (a *App) HandleSync(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
|
|
@ -122,7 +123,7 @@ func (a *App) makeSyncRequest(ctx context.Context, forceSend bool) error {
|
|||
return fmt.Errorf("error getting settings from context: %v ", err)
|
||||
}
|
||||
|
||||
onCallSync, err := a.GetSyncData(ctx, onCallPluginSettings)
|
||||
onCallSync, err := a.GetSyncData(onCallPluginSettings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting sync data: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
|
||||
import { PluginPageProps, PluginPage as RealPluginPage } from '@grafana/runtime';
|
||||
import { DEFAULT_PAGE } from 'helpers/consts';
|
||||
import { Header } from 'navbar/Header/Header';
|
||||
|
||||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
import { pages } from 'pages/pages';
|
||||
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
|
||||
import { DEFAULT_PAGE } from 'utils/consts';
|
||||
|
||||
interface AppPluginPageProps extends PluginPageProps {
|
||||
page?: string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { AppRootProps as BaseAppRootProps, AppPluginMeta, PluginConfigPageProps } from '@grafana/data';
|
||||
|
||||
import { getPluginId } from 'utils/consts';
|
||||
import { getPluginId } from 'helpers/consts';
|
||||
|
||||
export type OnCallPluginMetaJSONData = {
|
||||
stackId: number;
|
||||
|
|
@ -2,10 +2,10 @@ import React, { FC } from 'react';
|
|||
|
||||
import { cx } from '@emotion/css';
|
||||
import { Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { getCardButtonStyles } from './CardButton.styles';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
import { IconButton, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { bem, getUtilStyles } from 'styles/utils.styles';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
import { CheatSheetInterface, CheatSheetItem } from './CheatSheet.config';
|
||||
import { getCheatSheetStyles } from './CheatSheet.styles';
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { IconButton } from '@grafana/ui';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
interface CopyToClipboardProps {
|
||||
text: string;
|
||||
iconButtonProps?: Partial<Parameters<typeof IconButton>[0]>;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import React, { FC, useCallback, useEffect, useState } from 'react';
|
|||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Icon, Select, Stack } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
interface CursorPaginationProps {
|
||||
current: string;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
usePluginLinks as originalUsePluginLinks,
|
||||
} from '@grafana/runtime';
|
||||
import { Dropdown, ToolbarButton } from '@grafana/ui';
|
||||
import { OnCallPluginExtensionPoints } from 'types';
|
||||
import { OnCallPluginExtensionPoints } from 'app-types';
|
||||
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import React, { ReactElement, useMemo } from 'react';
|
|||
|
||||
import { locationUtil, PluginExtensionLink, PluginExtensionTypes } from '@grafana/data';
|
||||
import { IconName, Menu } from '@grafana/ui';
|
||||
import { getPluginId } from 'helpers/consts';
|
||||
import { truncateTitle } from 'helpers/string';
|
||||
|
||||
import { PluginBridge, SupportedPlugin } from 'components/PluginBridge/PluginBridge';
|
||||
import { getPluginId } from 'utils/consts';
|
||||
import { truncateTitle } from 'utils/string';
|
||||
|
||||
type Props = {
|
||||
extensions: PluginExtensionLink[];
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import React, { FC } from 'react';
|
|||
|
||||
import { css } from '@emotion/css';
|
||||
import { useStyles2, Stack } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import errorSVG from 'assets/img/error.svg';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
interface FullPageErrorProps {
|
||||
children?: React.ReactNode;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import React, { FC, ReactNode } from 'react';
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { isUserActionAllowed, UserAction } from 'helpers/authorization/authorization';
|
||||
|
||||
import { HamburgerMenuIcon } from 'components/HamburgerMenuIcon/HamburgerMenuIcon';
|
||||
import { WithContextMenu } from 'components/WithContextMenu/WithContextMenu';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { isUserActionAllowed, UserAction } from 'utils/authorization/authorization';
|
||||
|
||||
interface HamburgerContextMenuProps {
|
||||
items: Array<
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import React, { useEffect, useReducer } from 'react';
|
|||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Drawer, Icon, IconButton, Input, RadioButtonGroup, Select, Tooltip, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { GENERIC_ERROR, StackSize } from 'helpers/consts';
|
||||
import { openErrorNotification, openNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { GTable } from 'components/GTable/GTable';
|
||||
|
|
@ -15,8 +17,6 @@ import { ContactPoint } from 'models/alert_receive_channel/alert_receive_channel
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import styles from 'pages/integration/Integration.module.scss';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { GENERIC_ERROR, StackSize } from 'utils/consts';
|
||||
import { openErrorNotification, openNotification } from 'utils/utils';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
import { Icon, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { noop } from 'lodash-es';
|
||||
|
||||
import { IntegrationInputField } from 'components/IntegrationInputField/IntegrationInputField';
|
||||
|
|
@ -11,7 +12,6 @@ import { Text } from 'components/Text/Text';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import styles from 'pages/integration/Integration.module.scss';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import React, { useState } from 'react';
|
|||
|
||||
import { cx } from '@emotion/css';
|
||||
import { IconButton, Input, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { CopyToClipboardIcon } from 'components/CopyToClipboardIcon/CopyToClipboardIcon';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { getIntegrationInputFieldStyles } from './IntegrationInputField.styles';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Stack } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { IntegrationLogo, IntegrationLogoProps } from './IntegrationLogo';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useState } from 'react';
|
|||
|
||||
import { Button, Icon, Modal, Tooltip, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import Emoji from 'react-emoji-render';
|
||||
import { debounce } from 'throttle-debounce';
|
||||
|
|
@ -14,8 +16,6 @@ import { AlertReceiveChannelHelper } from 'models/alert_receive_channel/alert_re
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import styles from 'pages/integration/Integration.module.scss';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import React from 'react';
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Button, InlineLabel, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
|
||||
import { WithConfirm } from 'components/WithConfirm/WithConfirm';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
interface IntegrationTemplateBlockProps {
|
||||
label: string;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import React, { FC } from 'react';
|
|||
|
||||
import { LabelTag } from '@grafana/labels';
|
||||
import { Stack, Button, Tooltip } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
import { TooltipBadge } from 'components/TooltipBadge/TooltipBadge';
|
||||
import { LabelKeyValue } from 'models/label/label.types';
|
||||
import { components } from 'network/oncall-api/autogenerated-api.types';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
interface LabelsTooltipBadgeProps {
|
||||
labels: LabelKeyValue[];
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { FC, useCallback } from 'react';
|
|||
|
||||
import { css } from '@emotion/css';
|
||||
import { Button, Drawer, Field, TextArea, useStyles2, Stack } from '@grafana/ui';
|
||||
import { openWarningNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
||||
import { getUtilStyles } from 'styles/utils.styles';
|
||||
|
|
@ -11,7 +12,6 @@ import { prepareForUpdate } from 'containers/AddResponders/AddResponders.helpers
|
|||
import { AlertReceiveChannelStore } from 'models/alert_receive_channel/alert_receive_channel';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openWarningNotification } from 'utils/utils';
|
||||
|
||||
export type FormData = {
|
||||
message: string;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import React, { ComponentProps, FC, useCallback } from 'react';
|
|||
|
||||
import { CodeEditor, CodeEditorSuggestionItemKind, LoadingPlaceholder } from '@grafana/ui';
|
||||
import cn from 'classnames';
|
||||
|
||||
import { getPaths } from 'utils/utils';
|
||||
import { getPaths } from 'helpers/helpers';
|
||||
|
||||
import { conf, language as jinja2Language } from './jinja2';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import React, { FC, useCallback, useState } from 'react';
|
|||
|
||||
import { css } from '@emotion/css';
|
||||
import { Button, Drawer, Icon, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { ScheduleForm } from 'containers/ScheduleForm/ScheduleForm';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { Schedule, ScheduleType } from 'models/schedule/schedule.types';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
interface NewScheduleSelectorProps {
|
||||
onHide: () => void;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import React, { ReactElement, useEffect } from 'react';
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openWarningNotification } from 'helpers/helpers';
|
||||
|
||||
import { PluginLink } from 'components/PluginLink/PluginLink';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openWarningNotification } from 'utils/utils';
|
||||
|
||||
export interface PageBaseState {
|
||||
errorData: PageErrorData;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ import React, { FC, useCallback, useMemo } from 'react';
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { getPathFromQueryParams } from 'helpers/url';
|
||||
import { Link } from 'react-router-dom-v5-compat';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
|
||||
import { getPathFromQueryParams } from 'utils/url';
|
||||
|
||||
interface PluginLinkProps {
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import React, { ChangeEvent } from 'react';
|
|||
import { cx } from '@emotion/css';
|
||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
import { Button, Input, Select, IconButton, withTheme2 } from '@grafana/ui';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { openWarningNotification } from 'helpers/helpers';
|
||||
import { isNumber } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
import moment from 'moment-timezone';
|
||||
|
|
@ -30,8 +32,6 @@ import { UserGroup } from 'models/user_group/user_group.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { openWarningNotification } from 'utils/utils';
|
||||
|
||||
import { DragHandle } from './DragHandle';
|
||||
import { getEscalationPolicyStyles } from './EscalationPolicy.styles';
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import React from 'react';
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
import { Button, IconButton, Select, withTheme2 } from '@grafana/ui';
|
||||
import { UserAction } from 'helpers/authorization/authorization';
|
||||
import { openWarningNotification } from 'helpers/helpers';
|
||||
import { isNumber } from 'lodash';
|
||||
import { SortableElement } from 'react-sortable-hoc';
|
||||
|
||||
|
|
@ -15,8 +17,6 @@ import { ApiSchemas } from 'network/oncall-api/api.types';
|
|||
import { AppFeature } from 'state/features';
|
||||
import { RootStore } from 'state/rootStore';
|
||||
import { SelectOption } from 'state/types';
|
||||
import { UserAction } from 'utils/authorization/authorization';
|
||||
import { openWarningNotification } from 'utils/utils';
|
||||
|
||||
import { DragHandle } from './DragHandle';
|
||||
import { POLICY_DURATION_LIST_MINUTES, POLICY_DURATION_LIST_SECONDS } from './Policy.consts';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { FC, useEffect } from 'react';
|
|||
|
||||
import { cx } from '@emotion/css';
|
||||
import { Tooltip, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
import { getUtilStyles } from 'styles/utils.styles';
|
||||
|
||||
|
|
@ -12,7 +13,6 @@ import { Text } from 'components/Text/Text';
|
|||
import { TooltipBadge } from 'components/TooltipBadge/TooltipBadge';
|
||||
import { Schedule, ScheduleScoreQualityResult } from 'models/schedule/schedule.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { getScheduleQualityStyles } from './ScheduleQuality.styles';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import React, { FC, useCallback, useState } from 'react';
|
|||
|
||||
import { cx } from '@emotion/css';
|
||||
import { Icon, IconButton, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { bem, getUtilStyles } from 'styles/utils.styles';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { ScheduleScoreQualityResponse, ScheduleScoreQualityResult } from 'models/schedule/schedule.types';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { getScheduleQualityDetailsStyles } from './ScheduleQualityDetails.styles';
|
||||
import { ScheduleQualityProgressBar } from './ScheduleQualityProgressBar';
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ import React, { FC } from 'react';
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Button, IconButton, useStyles2 } from '@grafana/ui';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import { formatSourceCodeJsonString } from 'helpers/string';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
|
||||
import { formatSourceCodeJsonString } from 'utils/string';
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
interface SourceCodeProps {
|
||||
noMaxHeight?: boolean;
|
||||
noMinHeight?: boolean;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ import React, { FC, useEffect, useState } from 'react';
|
|||
import { css } from '@emotion/css';
|
||||
import { Tab, TabsBar, TabContent, useStyles2 } from '@grafana/ui';
|
||||
import cn from 'classnames';
|
||||
|
||||
import { LocationHelper } from 'utils/LocationHelper';
|
||||
import { LocationHelper } from 'helpers/LocationHelper';
|
||||
|
||||
interface TabConfig {
|
||||
label: string;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ import React, { FC, HTMLAttributes, ChangeEvent, useState, useCallback } from 'r
|
|||
|
||||
import { cx } from '@emotion/css';
|
||||
import { IconButton, Modal, Input, Stack, Button, useStyles2 } from '@grafana/ui';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
import { getTextStyles } from './Text.styles';
|
||||
|
||||
export type TextType = 'primary' | 'secondary' | 'disabled' | 'link' | 'success' | 'warning' | 'danger';
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import React, { ReactElement, useEffect, useRef, useState } from 'react';
|
|||
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { TEXT_ELLIPSIS_CLASS } from 'helpers/consts';
|
||||
|
||||
import styles from 'assets/style/utils.css';
|
||||
import { TEXT_ELLIPSIS_CLASS } from 'utils/consts';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import React, { FC } from 'react';
|
|||
|
||||
import { cx } from '@emotion/css';
|
||||
import { Icon, Tooltip, IconName, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
|
||||
import { Text, TextType } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { getTooltipBadgeStyles } from './TooltipBadge.styles';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import { css } from '@emotion/css';
|
|||
import { GrafanaTheme2, OrgRole } from '@grafana/data';
|
||||
import { Stack, useStyles2 } from '@grafana/ui';
|
||||
import { contextSrv } from 'grafana/app/core/core';
|
||||
import { UserAction } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { UserAction } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
type Props = {
|
||||
requiredUserAction: UserAction;
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|||
import { cx } from '@emotion/css';
|
||||
import { Stack, IconButton, useStyles2 } from '@grafana/ui';
|
||||
import { arrayMoveImmutable } from 'array-move';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
|
||||
import { bem } from 'styles/utils.styles';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { RemoteSelect } from 'containers/RemoteSelect/RemoteSelect';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import { fromPlainArray, toPlainArray } from './UserGroups.helpers';
|
||||
import { getUserGroupStyles } from './UserGroups.styles';
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ import React, { ChangeEvent, useCallback, useEffect, useRef } from 'react';
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Icon, Input, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { useDebouncedCallback } from 'utils/hooks';
|
||||
import { useDebouncedCallback } from 'helpers/hooks';
|
||||
|
||||
interface UsersFiltersProps {
|
||||
value: any;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import { css } from '@emotion/css';
|
|||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Stack, Badge, useStyles2, useTheme2 } from '@grafana/ui';
|
||||
import dayjs from 'dayjs';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { SourceCode } from 'components/SourceCode/SourceCode';
|
||||
import { Tabs } from 'components/Tabs/Tabs';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { getTzOffsetString } from 'models/timezone/timezone.helpers';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { WebhookStatusCodeBadge } from './WebhookStatusCodeBadge';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import React, { useState, useCallback, useMemo } from 'react';
|
|||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Modal, Alert, Stack, Icon, useStyles2 } from '@grafana/ui';
|
||||
import dayjs from 'dayjs';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
|
|
@ -11,8 +13,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { UserHelper } from 'models/user/user.helpers';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { getAddRespondersStyles } from './AddResponders.styles';
|
||||
import { NotificationPolicyValue, UserResponder as UserResponderType } from './AddResponders.types';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useState, useCallback, useEffect, useRef, FC } from 'react';
|
|||
|
||||
import { Alert, Icon, Input, LoadingPlaceholder, RadioButtonGroup, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { useDebouncedCallback, useOnClickOutside } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
import { ColumnsType } from 'rc-table/lib/interface';
|
||||
|
||||
|
|
@ -12,8 +14,6 @@ import { GrafanaTeam } from 'models/grafana_team/grafana_team.types';
|
|||
import { UserHelper } from 'models/user/user.helpers';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { useDebouncedCallback, useOnClickOutside } from 'utils/hooks';
|
||||
|
||||
import styles from './AddRespondersPopup.module.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useCallback } from 'react';
|
|||
|
||||
import { InlineSwitch, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { GSelect } from 'containers/GSelect/GSelect';
|
||||
|
|
@ -9,8 +11,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
||||
import { MSTeamsChannel } from 'models/msteams_channel/msteams_channel.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import styles from 'containers/AlertRules/parts/connectors/Connectors.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useCallback } from 'react';
|
|||
|
||||
import { InlineSwitch, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { GSelect } from 'containers/GSelect/GSelect';
|
||||
|
|
@ -10,8 +12,6 @@ import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
|||
import { PRIVATE_CHANNEL_NAME } from 'models/slack_channel/slack_channel.config';
|
||||
import { SlackChannel } from 'models/slack_channel/slack_channel.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import styles from './Connectors.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useCallback } from 'react';
|
|||
|
||||
import { InlineSwitch, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { GSelect } from 'containers/GSelect/GSelect';
|
||||
|
|
@ -9,8 +11,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
||||
import { TelegramChannel } from 'models/telegram_channel/telegram_channel.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import styles from './Connectors.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||
import { Alert } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { sanitize } from 'dompurify';
|
||||
import { LocationHelper } from 'helpers/LocationHelper';
|
||||
import { isUserActionAllowed, UserActions } from 'helpers/authorization/authorization';
|
||||
import { useForceUpdate, useQueryParams } from 'helpers/hooks';
|
||||
import { getItem, setItem } from 'helpers/localStorage';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { PluginLink } from 'components/PluginLink/PluginLink';
|
||||
|
|
@ -13,10 +17,6 @@ import { UserHelper } from 'models/user/user.helpers';
|
|||
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { LocationHelper } from 'utils/LocationHelper';
|
||||
import { isUserActionAllowed, UserActions } from 'utils/authorization/authorization';
|
||||
import { useForceUpdate, useQueryParams } from 'utils/hooks';
|
||||
import { getItem, setItem } from 'utils/localStorage';
|
||||
|
||||
import styles from './Alerts.module.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { HTMLAttributes, useState } from 'react';
|
|||
|
||||
import { Button, Field, Input, Label, Modal, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { openErrorNotification, openNotification } from 'helpers/helpers';
|
||||
import { get } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
|
@ -10,7 +11,6 @@ import { Controller, FormProvider, useForm } from 'react-hook-form';
|
|||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
import { SourceCode } from 'components/SourceCode/SourceCode';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openErrorNotification, openNotification } from 'utils/utils';
|
||||
|
||||
import styles from './ApiTokenForm.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ import React from 'react';
|
|||
|
||||
import { Button, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import {
|
||||
generateMissingPermissionMessage,
|
||||
isUserActionAllowed,
|
||||
UserActions,
|
||||
} from 'helpers/authorization/authorization';
|
||||
import { observer } from 'mobx-react';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
|
|
@ -12,7 +17,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { ApiToken } from 'models/api_token/api_token.types';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
import { generateMissingPermissionMessage, isUserActionAllowed, UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import { ApiTokenForm } from './ApiTokenForm';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React, { useCallback, useState } from 'react';
|
|||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Field, Icon, Modal, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { observer } from 'mobx-react';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
|
|
@ -12,7 +13,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { AlertGroupHelper } from 'models/alertgroup/alertgroup.helpers';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import styles from './AttachIncidentForm.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ import {
|
|||
} from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { Button, Checkbox, Icon, IconButton, LoadingPlaceholder, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { openErrorNotification } from 'helpers/helpers';
|
||||
import { useIsLoading } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||
|
||||
|
|
@ -28,9 +31,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { AlertGroupColumn, AlertGroupColumnType } from 'models/alertgroup/alertgroup.types';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { useIsLoading } from 'utils/hooks';
|
||||
import { openErrorNotification } from 'utils/utils';
|
||||
|
||||
import { getColumnsSelectorStyles } from './ColumnsSelector.styles';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ import React, { useMemo, useState } from 'react';
|
|||
import { LabelTag } from '@grafana/labels';
|
||||
import { Button, Checkbox, IconButton, Input, LoadingPlaceholder, Modal, Stack, useStyles2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { PROCESSING_REQUEST_ERROR, StackSize } from 'helpers/consts';
|
||||
import { WrapWithGlobalNotification } from 'helpers/decorators';
|
||||
import { pluralize } from 'helpers/helpers';
|
||||
import { useDebouncedCallback, useIsLoading } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import styles from 'assets/style/utils.css';
|
||||
|
|
@ -15,11 +20,6 @@ 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 { UserActions } from 'utils/authorization/authorization';
|
||||
import { PROCESSING_REQUEST_ERROR, StackSize } from 'utils/consts';
|
||||
import { WrapWithGlobalNotification } from 'utils/decorators';
|
||||
import { useDebouncedCallback, useIsLoading } from 'utils/hooks';
|
||||
import { pluralize } from 'utils/utils';
|
||||
|
||||
import { getColumnsSelectorWrapperStyles } from './ColumnsSelectorWrapper.styles';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useStyles2, Button, Icon, LoadingPlaceholder, Modal, Stack } from '@grafana/ui';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { PROCESSING_REQUEST_ERROR, StackSize } from 'helpers/consts';
|
||||
import { WrapAutoLoadingState, WrapWithGlobalNotification } from 'helpers/decorators';
|
||||
import { useIsLoading } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
|
|
@ -12,10 +16,6 @@ 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/authorization';
|
||||
import { PROCESSING_REQUEST_ERROR, StackSize } from 'utils/consts';
|
||||
import { WrapAutoLoadingState, WrapWithGlobalNotification } from 'utils/decorators';
|
||||
import { useIsLoading } from 'utils/hooks';
|
||||
|
||||
import { ColumnsModal } from './ColumnsModal';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import React, { FC, ReactElement } from 'react';
|
|||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { PluginPage } from 'PluginPage';
|
||||
import { AppRootProps } from 'app-types';
|
||||
import cn from 'classnames/bind';
|
||||
import { observer } from 'mobx-react';
|
||||
import { AppRootProps } from 'types';
|
||||
|
||||
import { Alerts } from 'containers/Alerts/Alerts';
|
||||
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useState, useCallback } from 'react';
|
|||
|
||||
import { Stack, Modal, Tooltip, Icon, Button } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openErrorNotification } from 'helpers/helpers';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
|
|
@ -13,8 +15,6 @@ import { AlertReceiveChannelHelper } from 'models/alert_receive_channel/alert_re
|
|||
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openErrorNotification } from 'utils/utils';
|
||||
|
||||
import styles from './EditRegexpRouteTemplateModal.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import React from 'react';
|
|||
|
||||
import { Stack, Badge } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { TeamName } from 'containers/TeamName/TeamName';
|
||||
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import styles from './EscalationChainCard.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { FC } from 'react';
|
|||
|
||||
import { Button, Field, Input, Modal, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { openWarningNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
|
|
@ -9,7 +10,6 @@ import { GSelect } from 'containers/GSelect/GSelect';
|
|||
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
|
||||
import { GrafanaTeam } from 'models/grafana_team/grafana_team.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openWarningNotification } from 'utils/utils';
|
||||
|
||||
import styles from 'containers/EscalationChainForm/EscalationChainForm.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { css } from '@emotion/css';
|
|||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { LoadingPlaceholder, Select, useStyles2, useTheme2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { observer } from 'mobx-react';
|
||||
import { getLabelBackgroundTextColorObject } from 'styles/utils.styles';
|
||||
|
||||
|
|
@ -14,7 +15,6 @@ import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/W
|
|||
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
|
||||
import { EscalationPolicyOption } from 'models/escalation_policy/escalation_policy.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import styles from './EscalationChainSteps.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ import React, { ReactElement, useCallback, useEffect } from 'react';
|
|||
import { SelectableValue } from '@grafana/data';
|
||||
import { AsyncMultiSelect, AsyncSelect } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { useDebouncedCallback } from 'helpers/hooks';
|
||||
import { get, isNil } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { useDebouncedCallback } from 'utils/hooks';
|
||||
|
||||
import styles from './GSelect.module.scss';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import React, { useCallback, useState } from 'react';
|
|||
|
||||
import { Button, Icon, Label, Modal, Tooltip, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { GSelect } from 'containers/GSelect/GSelect';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { GrafanaTeam } from 'models/grafana_team/grafana_team.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import styles from './GrafanaTeamSelect.module.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { useMemo, useState } from 'react';
|
|||
|
||||
import { ConfirmModal, Icon, IconName, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { IntegrationBlock } from 'components/Integrations/IntegrationBlock';
|
||||
|
|
@ -15,7 +16,6 @@ import { ApiSchemas } from 'network/oncall-api/api.types';
|
|||
import { CommonIntegrationHelper } from 'pages/integration/CommonIntegration.helper';
|
||||
import { IntegrationHelper } from 'pages/integration/Integration.helper';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import {
|
|||
Alert,
|
||||
} from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
|
|
@ -42,9 +45,6 @@ import { IntegrationHelper } from 'pages/integration/Integration.helper';
|
|||
import { MONACO_INPUT_HEIGHT_SMALL } from 'pages/integration/IntegrationCommon.config';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ import React, { ReactElement, useEffect, useState } from 'react';
|
|||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Drawer, Field, Icon, Select, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { IntegrationInputField } from 'components/IntegrationInputField/IntegrationInputField';
|
||||
|
|
@ -13,9 +16,6 @@ import { ApiSchemas } from 'network/oncall-api/api.types';
|
|||
import { SelectOption } from 'state/types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openNotification } from 'utils/utils';
|
||||
|
||||
import styles from './IntegrationHeartbeatForm.module.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { useState, useCallback } from 'react';
|
|||
|
||||
import { InlineSwitch, Tooltip } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { openErrorNotification, openNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { IntegrationBlockItem } from 'components/Integrations/IntegrationBlockItem';
|
||||
|
|
@ -16,7 +17,6 @@ import { IntegrationHelper } from 'pages/integration/Integration.helper';
|
|||
import styles from 'pages/integration/Integration.module.scss';
|
||||
import { MONACO_INPUT_HEIGHT_TALL } from 'pages/integration/IntegrationCommon.config';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openErrorNotification, openNotification } from 'utils/utils';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,17 @@ import {
|
|||
Stack,
|
||||
useStyles2,
|
||||
} from '@grafana/ui';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import {
|
||||
PLUGIN_ROOT,
|
||||
generateAssignToTeamInputDescription,
|
||||
DOCS_ROOT,
|
||||
INTEGRATION_SERVICENOW,
|
||||
StackSize,
|
||||
} from 'helpers/consts';
|
||||
import { useIsLoading } from 'helpers/hooks';
|
||||
import { validateURL } from 'helpers/string';
|
||||
import { OmitReadonlyMembers } from 'helpers/types';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Controller, useForm, useFormContext, FormProvider } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
|
@ -35,17 +46,6 @@ import { ApiSchemas } from 'network/oncall-api/api.types';
|
|||
import { IntegrationHelper, getIsBidirectionalIntegration } from 'pages/integration/Integration.helper';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import {
|
||||
PLUGIN_ROOT,
|
||||
generateAssignToTeamInputDescription,
|
||||
DOCS_ROOT,
|
||||
INTEGRATION_SERVICENOW,
|
||||
StackSize,
|
||||
} from 'utils/consts';
|
||||
import { useIsLoading } from 'utils/hooks';
|
||||
import { validateURL } from 'utils/string';
|
||||
import { OmitReadonlyMembers } from 'utils/types';
|
||||
|
||||
import { prepareForEdit } from './IntegrationForm.helpers';
|
||||
import { getIntegrationFormStyles } from './IntegrationForm.styles';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { useState, ChangeEvent } from 'react';
|
|||
|
||||
import { Drawer, Stack, Input, Tag, EmptySearchResult } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
|
|
@ -9,7 +10,6 @@ import { IntegrationLogo } from 'components/IntegrationLogo/IntegrationLogo';
|
|||
import { Text } from 'components/Text/Text';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import { IntegrationForm } from './IntegrationForm';
|
||||
import styles from './IntegrationFormContainer.module.scss';
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import React, { ChangeEvent, useState } from 'react';
|
|||
import { ServiceLabels } from '@grafana/labels';
|
||||
import { Alert, Button, Drawer, Dropdown, InlineSwitch, Input, Menu, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { DOCS_ROOT, GENERIC_ERROR, StackSize } from 'helpers/consts';
|
||||
import { openErrorNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { Collapse } from 'components/Collapse/Collapse';
|
||||
|
|
@ -16,8 +18,6 @@ import { LabelsErrors } from 'models/label/label.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { LabelTemplateOptions } from 'pages/integration/IntegrationCommon.config';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { DOCS_ROOT, GENERIC_ERROR, StackSize } from 'utils/consts';
|
||||
import { openErrorNotification } from 'utils/utils';
|
||||
|
||||
import { getIsAddBtnDisabled, getIsTooManyLabelsWarningVisible } from './IntegrationLabelsForm.helpers';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { useCallback, useState, useEffect } from 'react';
|
|||
|
||||
import { Button, Drawer, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { LocationHelper } from 'helpers/LocationHelper';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
|
|
@ -26,8 +28,6 @@ import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { IntegrationTemplateOptions, LabelTemplateOptions } from 'pages/integration/IntegrationCommon.config';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { LocationHelper } from 'utils/LocationHelper';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import styles from './IntegrationTemplate.module.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import React, { forwardRef, useImperativeHandle, useState } from 'react';
|
|||
|
||||
import { ServiceLabelsProps, ServiceLabels } from '@grafana/labels';
|
||||
import { Field, Label } from '@grafana/ui';
|
||||
import { GENERIC_ERROR } from 'helpers/consts';
|
||||
import { openErrorNotification } from 'helpers/helpers';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { splitToGroups } from 'models/label/label.helpers';
|
||||
import { LabelKeyValue } from 'models/label/label.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { GENERIC_ERROR } from 'utils/consts';
|
||||
import { openErrorNotification } from 'utils/utils';
|
||||
|
||||
export interface LabelsProps {
|
||||
value: LabelKeyValue[];
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import React, { FC } from 'react';
|
|||
|
||||
import { Button, Icon, Stack, Field, Input } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { openNotification, openWarningNotification } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
|
|
@ -10,8 +12,6 @@ import { PluginLink } from 'components/PluginLink/PluginLink';
|
|||
import { Text } from 'components/Text/Text';
|
||||
import MSTeamsLogo from 'icons/MSTeamsLogo';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { openNotification, openWarningNotification } from 'utils/utils';
|
||||
|
||||
import styles from './MSTeamsInstructions.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import React, { useCallback, useState, useEffect } from 'react';
|
|||
|
||||
import { Button, Modal } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { MSTeamsInstructions } from 'containers/MSTeams/MSTeamsInstructions';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import styles from './MSTeamsIntegrationButton.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import React, { useCallback } from 'react';
|
|||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Drawer, Field, Select, Stack, useStyles2 } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { openNotification, showApiError } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
import Emoji from 'react-emoji-render';
|
||||
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
||||
|
|
@ -14,8 +16,6 @@ import { AlertReceiveChannelHelper } from 'models/alert_receive_channel/alert_re
|
|||
import { MaintenanceMode } from 'models/alert_receive_channel/alert_receive_channel.types';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { openNotification, showApiError } from 'utils/utils';
|
||||
|
||||
import styles from './MaintenanceForm.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ jest.mock('plugin/GrafanaPluginRootPage.helpers', () => ({
|
|||
isTopNavbar: () => false,
|
||||
}));
|
||||
|
||||
jest.mock('utils/authorization/authorization', () => ({
|
||||
...jest.requireActual('utils/authorization/authorization'),
|
||||
jest.mock('helpers/authorization/authorization', () => ({
|
||||
...jest.requireActual('helpers/authorization/authorization'),
|
||||
isUserActionAllowed: jest.fn().mockReturnValue(true),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|||
|
||||
import { Button, Icon, LoadingPlaceholder, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { isMobile, openErrorNotification, openNotification, openWarningNotification } from 'helpers/helpers';
|
||||
import { useInitializePlugin } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import qrCodeImage from 'assets/img/qr-code.png';
|
||||
|
|
@ -15,10 +19,6 @@ import { UserHelper } from 'models/user/user.helpers';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { RootStore, rootStore as store } from 'state/rootStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { useInitializePlugin } from 'utils/hooks';
|
||||
import { isMobile, openErrorNotification, openNotification, openWarningNotification } from 'utils/utils';
|
||||
|
||||
import styles from './MobileAppConnection.module.scss';
|
||||
import { DisconnectButton } from './parts/DisconnectButton/DisconnectButton';
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import React, { FC } from 'react';
|
|||
|
||||
import { Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import AppleLogoSVG from 'assets/img/apple-logo.svg';
|
||||
import PlayStoreLogoSVG from 'assets/img/play-store-logo.svg';
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import styles from './DownloadIcons.module.scss';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Button, Stack } from '@grafana/ui';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
type Props = {
|
||||
baseUrl: string;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import React, { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'r
|
|||
|
||||
import { Button, ConfirmModal, ConfirmModalProps, Drawer, Input, Tab, TabsBar, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { PLUGIN_ROOT } from 'helpers/consts';
|
||||
import { KeyValuePair } from 'helpers/helpers';
|
||||
import { observer } from 'mobx-react';
|
||||
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
|
@ -15,9 +18,6 @@ import { ApiSchemas } from 'network/oncall-api/api.types';
|
|||
import { WebhookFormActionType } from 'pages/outgoing_webhooks/OutgoingWebhooks.types';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { PLUGIN_ROOT } from 'utils/consts';
|
||||
import { KeyValuePair } from 'utils/utils';
|
||||
|
||||
import { TemplateParams, WebhookFormFieldName } from './OutgoingWebhookForm.types';
|
||||
import { OutgoingWebhookFormFields } from './OutgoingWebhookFormFields';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Button, Field, Input, RadioButtonList, Select, Switch, useStyles2 } from '@grafana/ui';
|
||||
import { generateAssignToTeamInputDescription } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
import Emoji from 'react-emoji-render';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
|
|
@ -20,7 +21,6 @@ import {
|
|||
} from 'models/outgoing_webhook/outgoing_webhook.types';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { generateAssignToTeamInputDescription } from 'utils/consts';
|
||||
|
||||
import { getStyles } from './OutgoingWebhookForm.styles';
|
||||
import { TemplateParams, WebhookFormFieldName } from './OutgoingWebhookForm.types';
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
import { EmptySearchResult, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { StackSize } from 'helpers/consts';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
|
|
@ -11,7 +12,6 @@ import { Text } from 'components/Text/Text';
|
|||
import { getWebhookPresetIcons } from 'containers/OutgoingWebhookForm/WebhookPresetIcons.config';
|
||||
import { OutgoingWebhookPreset } from 'models/outgoing_webhook/outgoing_webhook.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { StackSize } from 'utils/consts';
|
||||
|
||||
import styles from 'containers/OutgoingWebhookForm/OutgoingWebhookForm.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import React from 'react';
|
|||
|
||||
import { Button, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { useCommonStyles } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import { WebhookLastEventDetails } from 'components/Webhooks/WebhookLastEventDetails';
|
||||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { useCommonStyles } from 'utils/hooks';
|
||||
|
||||
import styles from 'containers/OutgoingWebhookForm/OutgoingWebhookForm.module.css';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { useCallback } from 'react';
|
|||
|
||||
import { Button, Icon, LoadingPlaceholder, Stack, Tooltip } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { UserActions } from 'helpers/authorization/authorization';
|
||||
import { get } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
|
|
@ -14,7 +15,6 @@ import { NotificationPolicyType } from 'models/notification_policy/notification_
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
|
||||
import { getColor } from './PersonalNotificationSettings.helpers';
|
||||
import img from './img/default-step.png';
|
||||
|
|
|
|||
|
|
@ -3,17 +3,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2, PluginConfigPageProps, PluginMeta } from '@grafana/data';
|
||||
import { Alert, Field, Input, LoadingPlaceholder, useStyles2, Stack } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
import { OnCallPluginMetaJSONData } from 'types';
|
||||
|
||||
import { Button } from 'components/Button/Button';
|
||||
import { CollapsibleTreeView } from 'components/CollapsibleTreeView/CollapsibleTreeView';
|
||||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { rootStore } from 'state/rootStore';
|
||||
import { OnCallPluginMetaJSONData } from 'app-types';
|
||||
import {
|
||||
DEFAULT_PAGE,
|
||||
DOCS_ONCALL_OSS_INSTALL,
|
||||
|
|
@ -21,10 +11,20 @@ import {
|
|||
PLUGIN_CONFIG,
|
||||
PLUGIN_ROOT,
|
||||
REQUEST_HELP_URL,
|
||||
} from 'utils/consts';
|
||||
import { useOnMount } from 'utils/hooks';
|
||||
import { validateURL } from 'utils/string';
|
||||
import { getIsExternalServiceAccountFeatureAvailable, getIsRunningOpenSourceVersion } from 'utils/utils';
|
||||
} from 'helpers/consts';
|
||||
import { getIsExternalServiceAccountFeatureAvailable, getIsRunningOpenSourceVersion } from 'helpers/helpers';
|
||||
import { useOnMount } from 'helpers/hooks';
|
||||
import { validateURL } from 'helpers/string';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import { Button } from 'components/Button/Button';
|
||||
import { CollapsibleTreeView } from 'components/CollapsibleTreeView/CollapsibleTreeView';
|
||||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { ActionKey } from 'models/loader/action-keys';
|
||||
import { rootStore } from 'state/rootStore';
|
||||
|
||||
type PluginConfigFormValues = {
|
||||
onCallApiUrl: string;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Button, Stack, LoadingPlaceholder } from '@grafana/ui';
|
||||
import { REQUEST_HELP_URL, PLUGIN_CONFIG } from 'helpers/consts';
|
||||
import { getIsRunningOpenSourceVersion } from 'helpers/helpers';
|
||||
import { useInitializePlugin } from 'helpers/hooks';
|
||||
import { observer } from 'mobx-react';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import { FullPageError } from 'components/FullPageError/FullPageError';
|
||||
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
|
||||
import { REQUEST_HELP_URL, PLUGIN_CONFIG } from 'utils/consts';
|
||||
import { useInitializePlugin } from 'utils/hooks';
|
||||
import { getIsRunningOpenSourceVersion } from 'utils/utils';
|
||||
|
||||
interface PluginInitializerProps {
|
||||
children: React.ReactNode;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue