Merge pull request #4996 from grafana/dev

Merge instructions to main
This commit is contained in:
Michael Derynck 2024-09-06 09:35:59 -06:00 committed by GitHub
commit 64913ac47e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
243 changed files with 597 additions and 483 deletions

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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."
)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"],
]

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -1,4 +1,4 @@
module github.com/grafana-labs/grafana-oncall-app
module github.com/grafana/grafana-oncall-app
go 1.21.5

View file

@ -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)
}

View file

@ -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() {

View file

@ -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

View file

@ -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

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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

View file

@ -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)
}

View file

@ -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;

View file

@ -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;

View file

@ -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';

View file

@ -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';

View file

@ -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]>;

View file

@ -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;

View file

@ -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';

View file

@ -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[];

View file

@ -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;

View file

@ -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<

View file

@ -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);

View file

@ -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);

View file

@ -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';

View file

@ -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';

View file

@ -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);

View file

@ -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;

View file

@ -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[];

View file

@ -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;

View file

@ -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';

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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;

View file

@ -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;

View file

@ -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';

View file

@ -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);

View file

@ -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';

View file

@ -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;

View file

@ -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';

View file

@ -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;

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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);

View file

@ -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';

View file

@ -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);

View file

@ -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);

View file

@ -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';

View file

@ -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);

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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[];

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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),
}));

View file

@ -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';

View file

@ -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';

View file

@ -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;

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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;

View file

@ -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