mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
MSSQL: decouple plugin (#89597)
* decouple from core * yarn decouple * make health check work and azure config * f * driver error not needed * merge
This commit is contained in:
parent
4755eb5176
commit
eac194815e
@ -1084,7 +1084,7 @@
|
|||||||
"keywords": null
|
"keywords": null
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"grafanaDependency": "",
|
"grafanaDependency": "\u003e=10.4.0",
|
||||||
"grafanaVersion": "*",
|
"grafanaVersion": "*",
|
||||||
"plugins": []
|
"plugins": []
|
||||||
},
|
},
|
||||||
|
@ -48,7 +48,7 @@ const (
|
|||||||
func ProvideService(cfg *setting.Cfg) *Service {
|
func ProvideService(cfg *setting.Cfg) *Service {
|
||||||
logger := backend.NewLoggerWith("logger", "tsdb.mssql")
|
logger := backend.NewLoggerWith("logger", "tsdb.mssql")
|
||||||
return &Service{
|
return &Service{
|
||||||
im: datasource.NewInstanceManager(newInstanceSettings(cfg, logger)),
|
im: datasource.NewInstanceManager(NewInstanceSettings(cfg, logger)),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,12 +136,17 @@ func newMSSQL(ctx context.Context, driverName string, userFacingDefaultError str
|
|||||||
return db, handler, nil
|
return db, handler, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInstanceSettings(cfg *setting.Cfg, logger log.Logger) datasource.InstanceFactoryFunc {
|
func NewInstanceSettings(cfg *setting.Cfg, logger log.Logger) datasource.InstanceFactoryFunc {
|
||||||
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||||
|
grafCfg := backend.GrafanaConfigFromContext(ctx)
|
||||||
|
sqlCfg, err := grafCfg.SQL()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
jsonData := sqleng.JsonData{
|
jsonData := sqleng.JsonData{
|
||||||
MaxOpenConns: cfg.SqlDatasourceMaxOpenConnsDefault,
|
MaxOpenConns: sqlCfg.DefaultMaxOpenConns,
|
||||||
MaxIdleConns: cfg.SqlDatasourceMaxIdleConnsDefault,
|
MaxIdleConns: sqlCfg.DefaultMaxIdleConns,
|
||||||
ConnMaxLifetime: cfg.SqlDatasourceMaxConnLifetimeDefault,
|
ConnMaxLifetime: sqlCfg.DefaultMaxConnLifetimeSeconds,
|
||||||
Encrypt: "false",
|
Encrypt: "false",
|
||||||
ConnectionTimeout: 0,
|
ConnectionTimeout: 0,
|
||||||
SecureDSProxy: false,
|
SecureDSProxy: false,
|
||||||
@ -176,20 +181,22 @@ func newInstanceSettings(cfg *setting.Cfg, logger log.Logger) datasource.Instanc
|
|||||||
UID: settings.UID,
|
UID: settings.UID,
|
||||||
DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
|
DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
|
||||||
}
|
}
|
||||||
cnnstr, err := generateConnectionString(dsInfo, cfg, azureCredentials, kerberosAuth, logger)
|
cnnstr, err := generateConnectionString(dsInfo, cfg.Azure.ManagedIdentityClientId, cfg.Azure.AzureEntraPasswordCredentialsEnabled, azureCredentials, kerberosAuth, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Env == setting.Dev {
|
|
||||||
logger.Debug("GetEngine", "connection", cnnstr)
|
|
||||||
}
|
|
||||||
driverName := "mssql"
|
driverName := "mssql"
|
||||||
if jsonData.AuthenticationType == azureAuthentication {
|
if jsonData.AuthenticationType == azureAuthentication {
|
||||||
driverName = "azuresql"
|
driverName = "azuresql"
|
||||||
}
|
}
|
||||||
|
|
||||||
_, handler, err := newMSSQL(ctx, driverName, cfg.UserFacingDefaultError, cfg.DataProxyRowLimit, dsInfo, cnnstr, logger, settings)
|
userFacingDefaultError, err := grafCfg.UserFacingDefaultError()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, handler, err := newMSSQL(ctx, driverName, userFacingDefaultError, sqlCfg.RowLimit, dsInfo, cnnstr, logger, settings)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed connecting to MSSQL", "err", err)
|
logger.Error("Failed connecting to MSSQL", "err", err)
|
||||||
@ -230,7 +237,7 @@ func ParseURL(u string, logger DebugOnlyLogger) (*url.URL, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateConnectionString(dsInfo sqleng.DataSourceInfo, cfg *setting.Cfg, azureCredentials azcredentials.AzureCredentials, kerberosAuth kerberos.KerberosAuth, logger log.Logger) (string, error) {
|
func generateConnectionString(dsInfo sqleng.DataSourceInfo, azureManagedIdentityClientId string, azureEntraPasswordCredentialsEnabled bool, azureCredentials azcredentials.AzureCredentials, kerberosAuth kerberos.KerberosAuth, logger log.Logger) (string, error) {
|
||||||
const dfltPort = "0"
|
const dfltPort = "0"
|
||||||
var addr util.NetworkAddress
|
var addr util.NetworkAddress
|
||||||
if dsInfo.URL != "" {
|
if dsInfo.URL != "" {
|
||||||
@ -268,7 +275,7 @@ func generateConnectionString(dsInfo sqleng.DataSourceInfo, cfg *setting.Cfg, az
|
|||||||
|
|
||||||
switch dsInfo.JsonData.AuthenticationType {
|
switch dsInfo.JsonData.AuthenticationType {
|
||||||
case azureAuthentication:
|
case azureAuthentication:
|
||||||
azureCredentialDSNFragment, err := getAzureCredentialDSNFragment(azureCredentials, cfg)
|
azureCredentialDSNFragment, err := getAzureCredentialDSNFragment(azureCredentials, azureManagedIdentityClientId, azureEntraPasswordCredentialsEnabled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -305,12 +312,12 @@ func generateConnectionString(dsInfo sqleng.DataSourceInfo, cfg *setting.Cfg, az
|
|||||||
return connStr, nil
|
return connStr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAzureCredentialDSNFragment(azureCredentials azcredentials.AzureCredentials, cfg *setting.Cfg) (string, error) {
|
func getAzureCredentialDSNFragment(azureCredentials azcredentials.AzureCredentials, azureManagedIdentityClientId string, azureEntraPasswordCredentialsEnabled bool) (string, error) {
|
||||||
connStr := ""
|
connStr := ""
|
||||||
switch c := azureCredentials.(type) {
|
switch c := azureCredentials.(type) {
|
||||||
case *azcredentials.AzureManagedIdentityCredentials:
|
case *azcredentials.AzureManagedIdentityCredentials:
|
||||||
if cfg.Azure.ManagedIdentityClientId != "" {
|
if azureManagedIdentityClientId != "" {
|
||||||
connStr += fmt.Sprintf("user id=%s;", cfg.Azure.ManagedIdentityClientId)
|
connStr += fmt.Sprintf("user id=%s;", azureManagedIdentityClientId)
|
||||||
}
|
}
|
||||||
connStr += fmt.Sprintf("fedauth=%s;",
|
connStr += fmt.Sprintf("fedauth=%s;",
|
||||||
"ActiveDirectoryManagedIdentity")
|
"ActiveDirectoryManagedIdentity")
|
||||||
@ -322,7 +329,7 @@ func getAzureCredentialDSNFragment(azureCredentials azcredentials.AzureCredentia
|
|||||||
"ActiveDirectoryApplication",
|
"ActiveDirectoryApplication",
|
||||||
)
|
)
|
||||||
case *azcredentials.AzureEntraPasswordCredentials:
|
case *azcredentials.AzureEntraPasswordCredentials:
|
||||||
if cfg.Azure.AzureEntraPasswordCredentialsEnabled {
|
if azureEntraPasswordCredentialsEnabled {
|
||||||
connStr += fmt.Sprintf("user id=%s;password=%s;applicationclientid=%s;fedauth=%s;",
|
connStr += fmt.Sprintf("user id=%s;password=%s;applicationclientid=%s;fedauth=%s;",
|
||||||
c.UserId,
|
c.UserId,
|
||||||
c.Password,
|
c.Password,
|
||||||
@ -360,13 +367,7 @@ func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthReque
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dsHandler.Ping()
|
return dsHandler.CheckHealth(ctx, req)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return &backend.CheckHealthResult{Status: backend.HealthStatusError, Message: dsHandler.TransformQueryError(s.logger, err).Error()}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &backend.CheckHealthResult{Status: backend.HealthStatusOk, Message: "Database Connection OK"}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mssqlQueryResultTransformer) GetConverterList() []sqlutil.StringConverter {
|
func (t *mssqlQueryResultTransformer) GetConverterList() []sqlutil.StringConverter {
|
||||||
|
@ -1550,7 +1550,7 @@ func TestGenerateConnectionString(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
connStr, err := generateConnectionString(tc.dataSource, nil, nil, tc.kerberosCfg, logger)
|
connStr, err := generateConnectionString(tc.dataSource, "", false, nil, tc.kerberosCfg, logger)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, tc.expConnStr, connStr)
|
assert.Equal(t, tc.expConnStr, connStr)
|
||||||
})
|
})
|
||||||
|
@ -152,8 +152,13 @@ func (e *DataSourceHandler) Dispose() {
|
|||||||
e.log.Debug("DB disposed")
|
e.log.Debug("DB disposed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DataSourceHandler) Ping() error {
|
func (e *DataSourceHandler) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||||
return e.db.Ping()
|
err := e.db.Ping()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return &backend.CheckHealthResult{Status: backend.HealthStatusError, Message: e.TransformQueryError(e.log, err).Error()}, nil
|
||||||
|
}
|
||||||
|
return &backend.CheckHealthResult{Status: backend.HealthStatusOk, Message: "Database Connection OK"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DataSourceHandler) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
func (e *DataSourceHandler) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||||
|
28
pkg/tsdb/mssql/standalone/main.go
Normal file
28
pkg/tsdb/mssql/standalone/main.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb/mssql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Start listening to requests sent from Grafana. This call is blocking so
|
||||||
|
// it won't finish until Grafana shuts down the process or the plugin choose
|
||||||
|
// to exit by itself using os.Exit. Manage automatically manages life cycle
|
||||||
|
// of datasource instances. It accepts datasource instance factory as first
|
||||||
|
// argument. This factory will be automatically called on incoming request
|
||||||
|
// from Grafana to create different instances of SampleDatasource (per datasource
|
||||||
|
// ID). When datasource configuration changed Dispose method will be called and
|
||||||
|
// new datasource instance created using NewSampleDatasource factory.
|
||||||
|
logger := backend.NewLoggerWith("logger", "tsdb.mssql")
|
||||||
|
cfg := setting.NewCfg()
|
||||||
|
if err := datasource.Manage("mssql", mssql.NewInstanceSettings(cfg, logger), datasource.ManageOpts{}); err != nil {
|
||||||
|
log.DefaultLogger.Error(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
@ -17,8 +17,6 @@ const mixedPlugin = async () =>
|
|||||||
await import(/* webpackChunkName: "mixedPlugin" */ 'app/plugins/datasource/mixed/module');
|
await import(/* webpackChunkName: "mixedPlugin" */ 'app/plugins/datasource/mixed/module');
|
||||||
const prometheusPlugin = async () =>
|
const prometheusPlugin = async () =>
|
||||||
await import(/* webpackChunkName: "prometheusPlugin" */ 'app/plugins/datasource/prometheus/module');
|
await import(/* webpackChunkName: "prometheusPlugin" */ 'app/plugins/datasource/prometheus/module');
|
||||||
const mssqlPlugin = async () =>
|
|
||||||
await import(/* webpackChunkName: "mssqlPlugin" */ 'app/plugins/datasource/mssql/module');
|
|
||||||
const alertmanagerPlugin = async () =>
|
const alertmanagerPlugin = async () =>
|
||||||
await import(/* webpackChunkName: "alertmanagerPlugin" */ 'app/plugins/datasource/alertmanager/module');
|
await import(/* webpackChunkName: "alertmanagerPlugin" */ 'app/plugins/datasource/alertmanager/module');
|
||||||
|
|
||||||
@ -79,7 +77,6 @@ const builtInPlugins: Record<string, System.Module | (() => Promise<System.Modul
|
|||||||
'core:plugin/influxdb': influxdbPlugin,
|
'core:plugin/influxdb': influxdbPlugin,
|
||||||
'core:plugin/loki': lokiPlugin,
|
'core:plugin/loki': lokiPlugin,
|
||||||
'core:plugin/mixed': mixedPlugin,
|
'core:plugin/mixed': mixedPlugin,
|
||||||
'core:plugin/mssql': mssqlPlugin,
|
|
||||||
'core:plugin/prometheus': prometheusPlugin,
|
'core:plugin/prometheus': prometheusPlugin,
|
||||||
'core:plugin/alertmanager': alertmanagerPlugin,
|
'core:plugin/alertmanager': alertmanagerPlugin,
|
||||||
// panels
|
// panels
|
||||||
|
1
public/app/plugins/datasource/mssql/CHANGELOG.md
Normal file
1
public/app/plugins/datasource/mssql/CHANGELOG.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Changelog
|
@ -11,7 +11,9 @@ import {
|
|||||||
updateDatasourcePluginResetOption,
|
updateDatasourcePluginResetOption,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { ConfigSection, ConfigSubSection, DataSourceDescription } from '@grafana/experimental';
|
import { ConfigSection, ConfigSubSection, DataSourceDescription } from '@grafana/experimental';
|
||||||
|
import { config } from '@grafana/runtime';
|
||||||
import { ConnectionLimits, useMigrateDatabaseFields } from '@grafana/sql';
|
import { ConnectionLimits, useMigrateDatabaseFields } from '@grafana/sql';
|
||||||
|
import { NumberInput } from '@grafana/sql/src/components/configuration/NumberInput';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
FieldSet,
|
FieldSet,
|
||||||
@ -25,8 +27,6 @@ import {
|
|||||||
Field,
|
Field,
|
||||||
Switch,
|
Switch,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
|
|
||||||
import { config } from 'app/core/config';
|
|
||||||
|
|
||||||
import { AzureAuthSettings } from '../azureauth/AzureAuthSettings';
|
import { AzureAuthSettings } from '../azureauth/AzureAuthSettings';
|
||||||
import {
|
import {
|
||||||
@ -92,7 +92,10 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onConnectionTimeoutChanged = (connectionTimeout?: number) => {
|
const onConnectionTimeoutChanged = (connectionTimeout?: number) => {
|
||||||
updateDatasourcePluginJsonDataOption(props, 'connectionTimeout', connectionTimeout ?? 0);
|
if (connectionTimeout && connectionTimeout < 0) {
|
||||||
|
connectionTimeout = 0;
|
||||||
|
}
|
||||||
|
updateDatasourcePluginJsonDataOption(props, 'connectionTimeout', connectionTimeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildAuthenticationOptions = (): Array<SelectableValue<MSSQLAuthenticationType>> => {
|
const buildAuthenticationOptions = (): Array<SelectableValue<MSSQLAuthenticationType>> => {
|
||||||
@ -366,9 +369,8 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
|
|||||||
>
|
>
|
||||||
<NumberInput
|
<NumberInput
|
||||||
width={LONG_WIDTH}
|
width={LONG_WIDTH}
|
||||||
placeholder="60"
|
defaultValue={60}
|
||||||
min={0}
|
value={jsonData.connectionTimeout || 0}
|
||||||
value={jsonData.connectionTimeout}
|
|
||||||
onChange={onConnectionTimeoutChanged}
|
onChange={onConnectionTimeoutChanged}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
41
public/app/plugins/datasource/mssql/package.json
Normal file
41
public/app/plugins/datasource/mssql/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "@grafana-plugins/mssql",
|
||||||
|
"description": "MSSQL data source plugin",
|
||||||
|
"private": true,
|
||||||
|
"version": "11.3.0-pre",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/css": "11.11.2",
|
||||||
|
"@grafana/data": "workspace:*",
|
||||||
|
"@grafana/experimental": "1.7.12",
|
||||||
|
"@grafana/runtime": "11.3.0-pre",
|
||||||
|
"@grafana/sql": "11.3.0-pre",
|
||||||
|
"@grafana/ui": "11.3.0-pre",
|
||||||
|
"lodash": "4.17.21",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"rxjs": "7.8.1",
|
||||||
|
"tslib": "2.6.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@grafana/e2e-selectors": "workspace:*",
|
||||||
|
"@grafana/plugin-configs": "workspace:*",
|
||||||
|
"@testing-library/react": "15.0.2",
|
||||||
|
"@testing-library/user-event": "14.5.2",
|
||||||
|
"@types/jest": "29.5.12",
|
||||||
|
"@types/lodash": "4.17.4",
|
||||||
|
"@types/node": "20.14.2",
|
||||||
|
"@types/react": "18.3.3",
|
||||||
|
"@types/testing-library__jest-dom": "5.14.9",
|
||||||
|
"ts-node": "10.9.2",
|
||||||
|
"typescript": "5.4.5",
|
||||||
|
"webpack": "5.91.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@grafana/runtime": "*"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack -c ./webpack.config.ts --env production",
|
||||||
|
"build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)",
|
||||||
|
"dev": "webpack -w -c ./webpack.config.ts --env development"
|
||||||
|
},
|
||||||
|
"packageManager": "yarn@4.4.0"
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
"type": "datasource",
|
"type": "datasource",
|
||||||
"name": "Microsoft SQL Server",
|
"name": "Microsoft SQL Server",
|
||||||
"id": "mssql",
|
"id": "mssql",
|
||||||
|
"executable": "gpx_mssql",
|
||||||
"category": "sql",
|
"category": "sql",
|
||||||
|
|
||||||
"info": {
|
"info": {
|
||||||
@ -13,7 +14,11 @@
|
|||||||
"logos": {
|
"logos": {
|
||||||
"small": "img/sql_server_logo.svg",
|
"small": "img/sql_server_logo.svg",
|
||||||
"large": "img/sql_server_logo.svg"
|
"large": "img/sql_server_logo.svg"
|
||||||
}
|
},
|
||||||
|
"version": "%VERSION%"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"grafanaDependency": ">=10.4.0"
|
||||||
},
|
},
|
||||||
|
|
||||||
"alerting": true,
|
"alerting": true,
|
||||||
|
4
public/app/plugins/datasource/mssql/tsconfig.json
Normal file
4
public/app/plugins/datasource/mssql/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "@grafana/plugin-configs/tsconfig.json",
|
||||||
|
"include": ["."]
|
||||||
|
}
|
4
public/app/plugins/datasource/mssql/webpack.config.ts
Normal file
4
public/app/plugins/datasource/mssql/webpack.config.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import config from '@grafana/plugin-configs/webpack.config';
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-barrel-files/no-barrel-files
|
||||||
|
export default config;
|
47
yarn.lock
47
yarn.lock
@ -3102,6 +3102,37 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@grafana-plugins/mssql@workspace:public/app/plugins/datasource/mssql":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@grafana-plugins/mssql@workspace:public/app/plugins/datasource/mssql"
|
||||||
|
dependencies:
|
||||||
|
"@emotion/css": "npm:11.11.2"
|
||||||
|
"@grafana/data": "workspace:*"
|
||||||
|
"@grafana/e2e-selectors": "workspace:*"
|
||||||
|
"@grafana/experimental": "npm:1.7.12"
|
||||||
|
"@grafana/plugin-configs": "workspace:*"
|
||||||
|
"@grafana/runtime": "npm:11.3.0-pre"
|
||||||
|
"@grafana/sql": "npm:11.3.0-pre"
|
||||||
|
"@grafana/ui": "npm:11.3.0-pre"
|
||||||
|
"@testing-library/react": "npm:15.0.2"
|
||||||
|
"@testing-library/user-event": "npm:14.5.2"
|
||||||
|
"@types/jest": "npm:29.5.12"
|
||||||
|
"@types/lodash": "npm:4.17.4"
|
||||||
|
"@types/node": "npm:20.14.2"
|
||||||
|
"@types/react": "npm:18.3.3"
|
||||||
|
"@types/testing-library__jest-dom": "npm:5.14.9"
|
||||||
|
lodash: "npm:4.17.21"
|
||||||
|
react: "npm:18.2.0"
|
||||||
|
rxjs: "npm:7.8.1"
|
||||||
|
ts-node: "npm:10.9.2"
|
||||||
|
tslib: "npm:2.6.3"
|
||||||
|
typescript: "npm:5.4.5"
|
||||||
|
webpack: "npm:5.91.0"
|
||||||
|
peerDependencies:
|
||||||
|
"@grafana/runtime": "*"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@grafana-plugins/mysql@workspace:public/app/plugins/datasource/mysql":
|
"@grafana-plugins/mysql@workspace:public/app/plugins/datasource/mysql":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@grafana-plugins/mysql@workspace:public/app/plugins/datasource/mysql"
|
resolution: "@grafana-plugins/mysql@workspace:public/app/plugins/datasource/mysql"
|
||||||
@ -9821,6 +9852,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/lodash@npm:4.17.4":
|
||||||
|
version: 4.17.4
|
||||||
|
resolution: "@types/lodash@npm:4.17.4"
|
||||||
|
checksum: 10/3ec19f9fc48200006e71733e08bcb1478b0398673657fcfb21a8643d41a80bcce09a01000077c3b23a3c6d86b9b314abe0672a8fdfc0fd66b893bd41955cfab8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/logfmt@npm:^1.2.3":
|
"@types/logfmt@npm:^1.2.3":
|
||||||
version: 1.2.6
|
version: 1.2.6
|
||||||
resolution: "@types/logfmt@npm:1.2.6"
|
resolution: "@types/logfmt@npm:1.2.6"
|
||||||
@ -9932,6 +9970,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/node@npm:20.14.2":
|
||||||
|
version: 20.14.2
|
||||||
|
resolution: "@types/node@npm:20.14.2"
|
||||||
|
dependencies:
|
||||||
|
undici-types: "npm:~5.26.4"
|
||||||
|
checksum: 10/c38e47b190fa0a8bdfde24b036dddcf9401551f2fb170a90ff33625c7d6f218907e81c74e0fa6e394804a32623c24c60c50e249badc951007830f0d02c48ee0f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:^18.0.0":
|
"@types/node@npm:^18.0.0":
|
||||||
version: 18.19.33
|
version: 18.19.33
|
||||||
resolution: "@types/node@npm:18.19.33"
|
resolution: "@types/node@npm:18.19.33"
|
||||||
|
Loading…
Reference in New Issue
Block a user