Merge remote-tracking branch 'origin/main' into grafana-git-ui-sync

This commit is contained in:
Mariell Hoversholm committed 2025-01-14 13:11:03 +01:00
commit c8f85b04a9
48 files changed
+279 -303

No files matched your search

-2
View File
@@ -428,8 +428,6 @@
/packages/grafana-ui/src/graveyard/TimeSeries/ @grafana/dataviz-squad
/packages/grafana-ui/src/utils/storybook/ @grafana/plugins-platform-frontend
/plugins-bundled/ @grafana/plugins-platform-frontend
# root files, mostly frontend
/.browserslistrc @grafana/frontend-ops
/package.json @grafana/frontend-ops
+1 -2
View File
@@ -14,7 +14,6 @@
"public/**/*",
"packages/**/*",
"e2e/**/*",
"plugins-bundled/**/*",
"scripts/build/release-packages.sh",
"scripts/circle-release-next-packages.sh",
"scripts/ci-frontend-metrics.sh",
@@ -437,4 +436,4 @@
"action": "updateLabel",
"addLabel": "area/panel/table"
}
]
]
+1 -1
View File
@@ -19,7 +19,7 @@
"nx"
],
includePaths: ["package.json", "packages/**", "public/app/plugins/**"],
ignorePaths: ["emails/**", "plugins-bundled/**", "**/mocks/**"],
ignorePaths: ["emails/**", "**/mocks/**"],
labels: ["area/frontend", "dependencies", "no-changelog"],
postUpdateOptions: ["yarnDedupeHighest"],
packageRules: [
-1
View File
@@ -16,7 +16,6 @@ WORKDIR /tmp/grafana
COPY package.json project.json nx.json yarn.lock .yarnrc.yml ./
COPY .yarn .yarn
COPY packages packages
COPY plugins-bundled plugins-bundled
COPY public public
COPY LICENSE ./
COPY conf/defaults.ini ./conf/defaults.ini
-1
View File
@@ -211,7 +211,6 @@ build-cli: ## Build Grafana CLI application.
build-js: ## Build frontend assets.
@echo "build frontend"
yarn run build
yarn run plugins:build-bundled
PLUGIN_ID ?=
@@ -43,7 +43,7 @@ In order to access Explore, you must have either the `editor` or `administrator`
Refer to [Role-based access control (RBAC)](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/administration/roles-and-permissions/access-control/) in Grafana Enterprise to understand how you can manage Explore with role-based permissions.
{{< admonition type="note" >}}
If you are using Grafana Cloud, open a [support ticket in the Cloud Portal](/https://grafana.com/auth/sign-in) to enable the `viewers_can_edit` option.
If you are using Grafana Cloud, open a [support ticket in the Cloud Portal](https://grafana.com/auth/sign-in) to enable the `viewers_can_edit` option.
{{< /admonition >}}
## Explore elements
@@ -232,6 +232,7 @@ Experimental features might be changed or removed without prior notice.
| `k8SFolderCounts` | Enable folder's api server counts |
| `k8SFolderMove` | Enable folder's api server move |
| `teamHttpHeadersMimir` | Enables LBAC for datasources for Mimir to apply LBAC filtering of metrics to the client requests for users in teams |
| `queryLibraryDashboards` | Enables Query Library feature in Dashboards |
## Development feature toggles
+2 -3
View File
@@ -50,7 +50,7 @@
"themes-generate": "esbuild --target=es6 ./scripts/cli/generateSassVariableFiles.ts --bundle --platform=node --tsconfig=./scripts/cli/tsconfig.json | node",
"themes:usage": "eslint . --ignore-pattern '*.test.ts*' --ignore-pattern '*.spec.ts*' --cache --plugin '@grafana' --rule '{ @grafana/theme-token-usage: \"error\" }'",
"typecheck": "tsc --noEmit && yarn run packages:typecheck",
"plugins:build-bundled": "find plugins-bundled -name package.json -not -path '*/node_modules/*' -execdir yarn build \\;",
"plugins:build-bundled": "echo 'bundled plugins are no longer supported'",
"watch": "yarn start -d watch,start core:start --watchTheme",
"ci:test-frontend": "yarn run test:ci",
"i18n:stats": "node ./scripts/cli/reportI18nStats.mjs",
@@ -213,7 +213,7 @@
"ngtemplate-loader": "2.1.0",
"node-notifier": "10.0.1",
"nx": "19.8.2",
"postcss": "8.4.49",
"postcss": "8.5.1",
"postcss-loader": "8.1.1",
"postcss-reporter": "7.1.0",
"postcss-scss": "4.0.9",
@@ -437,7 +437,6 @@
"packages": [
"packages/*",
"packages/!(grafana-icons)/**",
"plugins-bundled/internal/*",
"public/app/plugins/*/*",
"e2e/test-plugins/*"
]
+1 -1
View File
@@ -51,7 +51,7 @@
"moment": "2.30.1",
"moment-timezone": "0.5.46",
"ol": "7.4.0",
"papaparse": "5.4.1",
"papaparse": "5.5.1",
"react-use": "17.6.0",
"rxjs": "7.8.1",
"string-hash": "^1.1.3",
@@ -252,4 +252,5 @@ export interface FeatureToggles {
teamHttpHeadersMimir?: boolean;
ABTestFeatureToggleA?: boolean;
ABTestFeatureToggleB?: boolean;
queryLibraryDashboards?: boolean;
}
+9
View File
@@ -57,3 +57,12 @@ export { hasPermission, hasPermissionInMetadata, hasAllPermissions, hasAnyPermis
export { QueryEditorWithMigration } from './components/QueryEditorWithMigration';
export { type MigrationHandler, isMigrationHandler, migrateQuery, migrateRequest } from './utils/migrationHandler';
export { usePluginUserStorage } from './utils/userStorage';
export {
type CorrelationsService,
type CorrelationData,
type CorrelationsData,
type CorrelationExternal,
type CorrelationQuery,
getCorrelationsService,
setCorrelationsService,
} from './services/CorrelationsService';
@@ -0,0 +1,126 @@
import {
DataFrame,
DataLinkPostProcessor,
DataLinkTransformationConfig,
DataSourceInstanceSettings,
TimeRange,
} from '@grafana/data';
export type CorrelationConfigQuery = {
field: string;
target: object; // for queries, this contains anything that would go in the query editor, so any extension off DataQuery a datasource would have, and needs to be generic.
transformations?: DataLinkTransformationConfig[];
};
export type CorrelationConfigExternal = {
field: string;
target: {
url: string; // For external, this simply contains a URL
};
transformations?: DataLinkTransformationConfig[];
};
type CorrelationBase = {
uid: string;
sourceUID: string;
label?: string;
description?: string;
provisioned: boolean;
orgId?: number;
};
/**
* @alpha
*/
export type CorrelationExternal = CorrelationBase & {
type: 'external';
config: CorrelationConfigExternal;
};
/**
* @alpha
*/
export type CorrelationQuery = CorrelationBase & {
type: 'query';
config: CorrelationConfigQuery;
targetUID: string;
};
/**
* @alpha
*/
export type CorrelationData =
| (Omit<CorrelationExternal, 'sourceUID'> & {
source: DataSourceInstanceSettings;
})
| (Omit<CorrelationQuery, 'sourceUID' | 'targetUID'> & {
source: DataSourceInstanceSettings;
target: DataSourceInstanceSettings;
});
/**
* @alpha
*/
export interface CorrelationsData {
correlations: CorrelationData[];
page: number;
limit: number;
totalCount: number;
}
/**
* Used to work with user defined correlations.
* Should be accessed via {@link getCorrelationsService} function.
*
* @alpha
*/
export interface CorrelationsService {
/**
* Creates data links in data frames from provided correlations
*
* @param dataFrames list of data frames to be processed
* @param correlations list of of possible correlations that can be applied
* @param dataFrameRefIdToDataSourceUid a map that for provided refId references corresponding data source ui
*/
attachCorrelationsToDataFrames: (
dataFrames: DataFrame[],
correlations: CorrelationData[],
dataFrameRefIdToDataSourceUid: Record<string, string>
) => DataFrame[];
/**
* Creates a link post processor function that handles correlation transformations
*
* @param timeRange The current time range
*/
correlationsDataLinkPostProcessorFactory: (timeRange: TimeRange) => DataLinkPostProcessor;
/**
* Loads all the correlations defined for the given data sources.
*
* @param sourceUIDs Data source UIDs
*/
getCorrelationsBySourceUIDs: (sourceUIDs: string[]) => Promise<CorrelationsData>;
}
let singletonInstance: CorrelationsService;
/**
* Used during startup by Grafana to set the CorrelationsService so it is available
* via {@link getCorrelationsService} to the rest of the application.
*
* @internal
*/
export function setCorrelationsService(instance: CorrelationsService) {
console.log('setCorrelationsService', instance);
singletonInstance = instance;
}
/**
* Used to retrieve the {@link CorrelationsService}.
*
* @alpha
*/
export function getCorrelationsService(): CorrelationsService {
return singletonInstance;
}
+2 -2
View File
@@ -95,7 +95,7 @@ func (m *PluginInstaller) install(ctx context.Context, pluginID, version string,
return nil, err
}
if plugin, exists := m.plugin(ctx, pluginID, version); exists {
if plugin.IsCorePlugin() || plugin.IsBundledPlugin() {
if plugin.IsCorePlugin() {
return nil, plugins.ErrInstallCorePlugin
}
@@ -194,7 +194,7 @@ func (m *PluginInstaller) Remove(ctx context.Context, pluginID, version string)
return plugins.ErrPluginNotInstalled
}
if plugin.IsCorePlugin() || plugin.IsBundledPlugin() {
if plugin.IsCorePlugin() {
return plugins.ErrUninstallCorePlugin
}
+18 -27
View File
@@ -212,37 +212,28 @@ func TestPluginManager_Add_Remove(t *testing.T) {
})
})
t.Run("Can't update core or bundled plugin", func(t *testing.T) {
tcs := []struct {
class plugins.Class
}{
{class: plugins.ClassCore},
{class: plugins.ClassBundled},
t.Run("Can't update core plugin", func(t *testing.T) {
p := createPlugin(t, testPluginID, plugins.ClassCore, true, true, func(plugin *plugins.Plugin) {
plugin.Info.Version = "1.0.0"
})
reg := &fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
testPluginID: p,
},
}
for _, tc := range tcs {
p := createPlugin(t, testPluginID, tc.class, true, true, func(plugin *plugins.Plugin) {
plugin.Info.Version = "1.0.0"
})
pm := New(reg, &fakes.FakeLoader{}, &fakes.FakePluginRepo{}, &fakes.FakePluginStorage{}, storage.SimpleDirNameGeneratorFunc, &fakes.FakeAuthService{})
err := pm.Add(context.Background(), p.ID, "3.2.0", testCompatOpts())
require.ErrorIs(t, err, plugins.ErrInstallCorePlugin)
reg := &fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
testPluginID: p,
},
}
err = pm.Add(context.Background(), testPluginID, "", testCompatOpts())
require.Equal(t, plugins.ErrInstallCorePlugin, err)
pm := New(reg, &fakes.FakeLoader{}, &fakes.FakePluginRepo{}, &fakes.FakePluginStorage{}, storage.SimpleDirNameGeneratorFunc, &fakes.FakeAuthService{})
err := pm.Add(context.Background(), p.ID, "3.2.0", testCompatOpts())
require.ErrorIs(t, err, plugins.ErrInstallCorePlugin)
err = pm.Add(context.Background(), testPluginID, "", testCompatOpts())
require.Equal(t, plugins.ErrInstallCorePlugin, err)
t.Run(fmt.Sprintf("Can't uninstall %s plugin", tc.class), func(t *testing.T) {
err = pm.Remove(context.Background(), p.ID, p.Info.Version)
require.Equal(t, plugins.ErrUninstallCorePlugin, err)
})
}
t.Run("Can't uninstall core plugin", func(t *testing.T) {
err = pm.Remove(context.Background(), p.ID, p.Info.Version)
require.Equal(t, plugins.ErrUninstallCorePlugin, err)
})
})
t.Run("Can install multiple dependency levels", func(t *testing.T) {
-50
View File
@@ -124,56 +124,6 @@ func TestLoader_Load(t *testing.T) {
},
},
},
{
name: "Load a Bundled plugin",
class: plugins.ClassBundled,
cfg: &config.PluginManagementCfg{},
pluginPaths: []string{"../testdata/valid-v2-signature"},
want: []*plugins.Plugin{
{
JSONData: plugins.JSONData{
ID: "test-datasource",
Type: plugins.TypeDataSource,
Name: "Test",
Info: plugins.Info{
Author: plugins.InfoLink{
Name: "Will Browne",
URL: "https://willbrowne.com",
},
Version: "1.0.0",
Logos: plugins.Logos{
Small: "public/img/icn-datasource.svg",
Large: "public/img/icn-datasource.svg",
},
Description: "Test",
},
Dependencies: plugins.Dependencies{
GrafanaVersion: "*",
Plugins: []plugins.Dependency{},
Extensions: plugins.ExtensionsDependencies{
ExposedComponents: []string{},
},
},
Extensions: plugins.Extensions{
AddedLinks: []plugins.AddedLink{},
AddedComponents: []plugins.AddedComponent{},
ExposedComponents: []plugins.ExposedComponent{},
ExtensionPoints: []plugins.ExtensionPoint{},
},
Executable: "test",
Backend: true,
State: "alpha",
},
Module: "public/plugins/test-datasource/module.js",
BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/valid-v2-signature/plugin/")),
Signature: "valid",
SignatureType: plugins.SignatureTypeGrafana,
SignatureOrg: "Grafana Labs",
Class: plugins.ClassBundled,
},
},
},
{
name: "Load plugin with symbolic links",
class: plugins.ClassExternal,
+1 -1
View File
@@ -49,7 +49,7 @@ func (s *Validation) ValidateSignature(plugin *plugins.Plugin) error {
}
}
if plugin.IsCorePlugin() || plugin.IsBundledPlugin() {
if plugin.IsCorePlugin() {
return nil
}
-1
View File
@@ -24,7 +24,6 @@ func ProvideService(cfg *setting.Cfg) *Service {
func (s *Service) List(_ context.Context) []plugins.PluginSource {
r := []plugins.PluginSource{
NewLocalSource(plugins.ClassCore, corePluginPaths(s.cfg.StaticRootPath)),
NewLocalSource(plugins.ClassBundled, []string{s.cfg.BundledPluginsPath}),
}
r = append(r, s.externalPluginSources()...)
r = append(r, s.pluginSettingSources()...)
+11 -23
View File
@@ -17,9 +17,8 @@ func TestSources_List(t *testing.T) {
require.NoError(t, err)
cfg := &setting.Cfg{
StaticRootPath: testdata,
PluginsPath: filepath.Join(testdata, "pluginRootWithDist"),
BundledPluginsPath: filepath.Join(testdata, "unsigned-panel"),
StaticRootPath: testdata,
PluginsPath: filepath.Join(testdata, "pluginRootWithDist"),
PluginSettings: setting.PluginSettings{
"foo": map[string]string{
"path": filepath.Join(testdata, "test-app"),
@@ -35,7 +34,7 @@ func TestSources_List(t *testing.T) {
ctx := context.Background()
require.Len(t, srcs, 6)
require.Len(t, srcs, 5)
require.Equal(t, srcs[0].PluginClass(ctx), plugins.ClassCore)
require.Equal(t, srcs[0].PluginURIs(ctx), []string{
@@ -48,15 +47,17 @@ func TestSources_List(t *testing.T) {
require.Equal(t, plugins.SignatureType(""), sig.Type)
require.Equal(t, "", sig.SigningOrg)
require.Equal(t, srcs[1].PluginClass(ctx), plugins.ClassBundled)
require.Equal(t, srcs[1].PluginURIs(ctx), []string{filepath.Join(testdata, "unsigned-panel")})
require.Equal(t, srcs[1].PluginClass(ctx), plugins.ClassExternal)
require.Equal(t, srcs[1].PluginURIs(ctx), []string{
filepath.Join(testdata, "pluginRootWithDist", "datasource"),
})
sig, exists = srcs[1].DefaultSignature(ctx)
require.False(t, exists)
require.Equal(t, plugins.Signature{}, sig)
require.Equal(t, srcs[2].PluginClass(ctx), plugins.ClassExternal)
require.Equal(t, srcs[2].PluginURIs(ctx), []string{
filepath.Join(testdata, "pluginRootWithDist", "datasource"),
filepath.Join(testdata, "pluginRootWithDist", "dist"),
})
sig, exists = srcs[2].DefaultSignature(ctx)
require.False(t, exists)
@@ -64,17 +65,9 @@ func TestSources_List(t *testing.T) {
require.Equal(t, srcs[3].PluginClass(ctx), plugins.ClassExternal)
require.Equal(t, srcs[3].PluginURIs(ctx), []string{
filepath.Join(testdata, "pluginRootWithDist", "dist"),
})
sig, exists = srcs[3].DefaultSignature(ctx)
require.False(t, exists)
require.Equal(t, plugins.Signature{}, sig)
require.Equal(t, srcs[4].PluginClass(ctx), plugins.ClassExternal)
require.Equal(t, srcs[4].PluginURIs(ctx), []string{
filepath.Join(testdata, "pluginRootWithDist", "panel"),
})
sig, exists = srcs[4].DefaultSignature(ctx)
sig, exists = srcs[3].DefaultSignature(ctx)
require.False(t, exists)
require.Equal(t, plugins.Signature{}, sig)
})
@@ -84,9 +77,8 @@ func TestSources_List(t *testing.T) {
require.NoError(t, err)
cfg := &setting.Cfg{
StaticRootPath: testdata,
PluginsPath: filepath.Join(testdata, "symbolic-plugin-dirs"),
BundledPluginsPath: filepath.Join(testdata, "unsigned-panel"),
StaticRootPath: testdata,
PluginsPath: filepath.Join(testdata, "symbolic-plugin-dirs"),
}
s := ProvideService(cfg)
ctx := context.Background()
@@ -107,10 +99,6 @@ func TestSources_List(t *testing.T) {
filepath.Join(testdata, "app", "plugins", "panel"): {},
}, "should include core plugins")
require.Equal(t, uris[plugins.ClassBundled], map[string]struct{}{
filepath.Join(testdata, "unsigned-panel"): {},
}, "should include bundle plugin")
require.Equal(t, uris[plugins.ClassExternal], map[string]struct{}{
filepath.Join(testdata, "symbolic-plugin-dirs", "plugin"): {},
}, "should include external symlinked plugin")
+1 -6
View File
@@ -494,19 +494,14 @@ func (p *Plugin) IsCorePlugin() bool {
return p.Class == ClassCore
}
func (p *Plugin) IsBundledPlugin() bool {
return p.Class == ClassBundled
}
func (p *Plugin) IsExternalPlugin() bool {
return !p.IsCorePlugin() && !p.IsBundledPlugin()
return !p.IsCorePlugin()
}
type Class string
const (
ClassCore Class = "core"
ClassBundled Class = "bundled"
ClassExternal Class = "external"
ClassCDN Class = "cdn"
)
+7
View File
@@ -1743,6 +1743,13 @@ var (
Expression: "false",
HideFromDocs: true,
},
{
Name: "queryLibraryDashboards",
Description: "Enables Query Library feature in Dashboards",
Stage: FeatureStageExperimental,
Owner: grafanaFrontendPlatformSquad,
AllowSelfServe: false,
},
}
)
+1
View File
@@ -233,3 +233,4 @@ improvedExternalSessionHandlingSAML,preview,@grafana/identity-access-team,false,
teamHttpHeadersMimir,experimental,@grafana/identity-access-team,false,false,false
ABTestFeatureToggleA,experimental,@grafana/sharing-squad,false,false,false
ABTestFeatureToggleB,experimental,@grafana/sharing-squad,false,false,false
queryLibraryDashboards,experimental,@grafana/grafana-frontend-platform,false,false,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
233 teamHttpHeadersMimir experimental @grafana/identity-access-team false false false
234 ABTestFeatureToggleA experimental @grafana/sharing-squad false false false
235 ABTestFeatureToggleB experimental @grafana/sharing-squad false false false
236 queryLibraryDashboards experimental @grafana/grafana-frontend-platform false false false
+4
View File
@@ -942,4 +942,8 @@ const (
// FlagABTestFeatureToggleB
// Test feature toggle to see how cohorts could be set up AB testing
FlagABTestFeatureToggleB = "ABTestFeatureToggleB"
// FlagQueryLibraryDashboards
// Enables Query Library feature in Dashboards
FlagQueryLibraryDashboards = "queryLibraryDashboards"
)
+15
View File
@@ -3210,6 +3210,21 @@
"codeowner": "@grafana/grafana-frontend-platform"
}
},
{
"metadata": {
"name": "queryLibraryDashboards",
"resourceVersion": "1736850377404",
"creationTimestamp": "2025-01-14T10:24:54Z",
"annotations": {
"grafana.app/updatedTimestamp": "2025-01-14 10:26:17.404592 +0000 UTC"
}
},
"spec": {
"description": "Enables Query Library feature in Dashboards",
"stage": "experimental",
"codeowner": "@grafana/grafana-frontend-platform"
}
},
{
"metadata": {
"name": "queryOverLive",
@@ -124,56 +124,6 @@ func TestLoader_Load(t *testing.T) {
},
},
},
{
name: "Load a Bundled plugin",
class: plugins.ClassBundled,
cfg: &config.PluginManagementCfg{},
pluginPaths: []string{filepath.Join(testDataDir(t), "valid-v2-signature")},
want: []*plugins.Plugin{
{
JSONData: plugins.JSONData{
ID: "test-datasource",
Type: plugins.TypeDataSource,
Name: "Test",
Info: plugins.Info{
Author: plugins.InfoLink{
Name: "Will Browne",
URL: "https://willbrowne.com",
},
Version: "1.0.0",
Logos: plugins.Logos{
Small: "public/img/icn-datasource.svg",
Large: "public/img/icn-datasource.svg",
},
Description: "Test",
},
Dependencies: plugins.Dependencies{
GrafanaVersion: "*",
Plugins: []plugins.Dependency{},
Extensions: plugins.ExtensionsDependencies{
ExposedComponents: []string{},
},
},
Extensions: plugins.Extensions{
AddedLinks: []plugins.AddedLink{},
AddedComponents: []plugins.AddedComponent{},
ExposedComponents: []plugins.ExposedComponent{},
ExtensionPoints: []plugins.ExtensionPoint{},
},
Executable: "test",
Backend: true,
State: "alpha",
},
Module: "public/plugins/test-datasource/module.js",
BaseURL: "public/plugins/test-datasource",
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "valid-v2-signature/plugin/")),
Signature: "valid",
SignatureType: plugins.SignatureTypeGrafana,
SignatureOrg: "Grafana Labs",
Class: plugins.ClassBundled,
},
},
},
{
name: "Load plugin with symbolic links",
class: plugins.ClassExternal,
@@ -672,7 +622,7 @@ func TestLoader_Load_CustomSource(t *testing.T) {
},
},
FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "cdn/plugin")),
Class: plugins.ClassBundled,
Class: plugins.ClassExternal,
Signature: plugins.SignatureStatusValid,
BaseURL: "https://cdn.example.com/grafana-worldmap-panel/0.3.3/public/plugins/grafana-worldmap-panel",
Module: "https://cdn.example.com/grafana-worldmap-panel/0.3.3/public/plugins/grafana-worldmap-panel/module.js",
@@ -681,7 +631,7 @@ func TestLoader_Load_CustomSource(t *testing.T) {
l := newLoader(t, cfg, fakes.NewFakePluginRegistry(), fakes.NewFakeProcessManager(), fakes.NewFakeBackendProcessProvider(), newFakeErrorTracker())
got, err := l.Load(context.Background(), &fakes.FakePluginSource{
PluginClassFunc: func(ctx context.Context) plugins.Class {
return plugins.ClassBundled
return plugins.ClassExternal
},
PluginURIsFunc: func(ctx context.Context) []string {
return pluginPaths
@@ -1170,11 +1120,6 @@ func TestLoader_AngularClass(t *testing.T) {
class: plugins.ClassCore,
expAngularDetectionRun: false,
},
{
name: "bundled plugin should skip angular detection",
class: plugins.ClassBundled,
expAngularDetectionRun: false,
},
{
name: "external plugin should run angular detection",
class: plugins.ClassExternal,
@@ -121,9 +121,9 @@ func (r *RegisterActionSets) Register(ctx context.Context, p *plugins.Plugin) (*
return p, nil
}
// ReportBuildMetrics reports build information for all plugins, except core and bundled plugins.
// ReportBuildMetrics reports build information for all plugins, except core plugins.
func ReportBuildMetrics(_ context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
if !p.IsCorePlugin() && !p.IsBundledPlugin() {
if !p.IsCorePlugin() {
metrics.SetPluginBuildInformation(p.ID, string(p.Type), p.Info.Version, string(p.Signature))
}
@@ -55,15 +55,11 @@ func TestIntegrationPluginManager(t *testing.T) {
staticRootPath, err := filepath.Abs("../../../public/")
require.NoError(t, err)
bundledPluginsPath, err := filepath.Abs("../../../plugins-bundled/internal")
require.NoError(t, err)
features := featuremgmt.WithFeatures()
cfg := &setting.Cfg{
Raw: ini.Empty(),
StaticRootPath: staticRootPath,
BundledPluginsPath: bundledPluginsPath,
Azure: &azsettings.AzureSettings{},
Raw: ini.Empty(),
StaticRootPath: staticRootPath,
Azure: &azsettings.AzureSettings{},
PluginSettings: map[string]map[string]string{
"test-app": {
"path": "../../plugins/manager/testdata/test-app",
@@ -27,7 +27,7 @@ func TestStore_ProvideService(t *testing.T) {
return []plugins.PluginSource{
&fakes.FakePluginSource{
PluginClassFunc: func(ctx context.Context) plugins.Class {
return plugins.ClassBundled
return "foobar"
},
PluginURIsFunc: func(ctx context.Context) []string {
return []string{"path1"}
+1 -1
View File
@@ -165,7 +165,7 @@ func TestPluginUpdateChecker_checkForUpdates(t *testing.T) {
Info: plugins.Info{Version: "2.5.7"},
Type: plugins.TypePanel,
},
Class: plugins.ClassBundled,
Class: plugins.ClassExternal,
},
{
JSONData: plugins.JSONData{
+2 -2
View File
@@ -135,7 +135,6 @@ type Cfg struct {
DataPath string
LogsPath string
PluginsPath string
BundledPluginsPath string
EnterpriseLicensePath string
// SMTP email settings
@@ -1102,7 +1101,8 @@ func (cfg *Cfg) parseINIFile(iniFile *ini.File) error {
cfg.InstanceName = valueAsString(iniFile.Section(""), "instance_name", "unknown_instance_name")
plugins := valueAsString(iniFile.Section("paths"), "plugins", "")
cfg.PluginsPath = makeAbsolute(plugins, cfg.HomePath)
cfg.BundledPluginsPath = makeAbsolute("plugins-bundled", cfg.HomePath)
provisioning := valueAsString(iniFile.Section("paths"), "provisioning", "")
cfg.ProvisioningPath = makeAbsolute(provisioning, cfg.HomePath)
if err := cfg.readServerSettings(iniFile); err != nil {
return err
+1 -1
View File
@@ -100,7 +100,7 @@ func TestIntegrationPlugins(t *testing.T) {
t.Run("List", func(t *testing.T) {
testCases := []testCase{
{
desc: "should return all loaded core and bundled plugins",
desc: "should return all loaded core plugins",
url: "http://%s/api/plugins",
expStatus: http.StatusOK,
expRespPath: "expectedListResp.json",
-9
View File
@@ -1,9 +0,0 @@
# packaged by toolkit
dist
coverage
# Ignore external git configs
external
# this file is added automatically
.prettierrc.js
-5
View File
@@ -1,5 +0,0 @@
# Bundled Plugins
Bundled plugins are built as true plugins, and managed by the grafana install.
TODO: the packaging system should move all `dist` items to the root and remove sources.
-3
View File
@@ -1,3 +0,0 @@
{
"plugins": []
}
+3
View File
@@ -40,6 +40,7 @@ import {
setCurrentUser,
setChromeHeaderHeightHook,
setPluginLinksHook,
setCorrelationsService,
} from '@grafana/runtime';
import { setPanelDataErrorView } from '@grafana/runtime/src/components/PanelDataErrorView';
import { setPanelRenderer } from '@grafana/runtime/src/components/PanelRenderer';
@@ -60,6 +61,7 @@ import { initializeCrashDetection } from './core/crash';
import { initializeI18n } from './core/internationalization';
import { setMonacoEnv } from './core/monacoEnv';
import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks';
import { CorrelationsService } from './core/services/CorrelationsService';
import { NewFrontendAssetsChecker } from './core/services/NewFrontendAssetsChecker';
import { backendSrv } from './core/services/backend_srv';
import { contextSrv, RedirectToUrlKey } from './core/services/context_srv';
@@ -146,6 +148,7 @@ export class GrafanaApp {
setPluginPage(PluginPage);
setPanelDataErrorView(PanelDataErrorView);
setLocationSrv(locationService);
setCorrelationsService(new CorrelationsService());
setEmbeddedDashboard(EmbeddedDashboardLazy);
setTimeZoneResolver(() => config.bootData.user.timezone);
initGrafanaLive();
@@ -0,0 +1,22 @@
import { DataFrame, TimeRange } from '@grafana/data';
import type { CorrelationData, CorrelationsService as CorrelationsServiceInterface } from '@grafana/runtime';
import { attachCorrelationsToDataFrames, getCorrelationsBySourceUIDs } from 'app/features/correlations/utils';
import { exploreDataLinkPostProcessorFactory } from 'app/features/explore/utils/links';
export class CorrelationsService implements CorrelationsServiceInterface {
attachCorrelationsToDataFrames(
dataFrames: DataFrame[],
correlations: CorrelationData[],
dataFrameRefIdToDataSourceUid: Record<string, string>
) {
return attachCorrelationsToDataFrames(dataFrames, correlations, dataFrameRefIdToDataSourceUid);
}
correlationsDataLinkPostProcessorFactory(timeRange: TimeRange) {
return exploreDataLinkPostProcessorFactory(undefined, timeRange);
}
getCorrelationsBySourceUIDs(sourceUIDs: string[]) {
return getCorrelationsBySourceUIDs(sourceUIDs);
}
}
@@ -3,7 +3,7 @@ import { negate } from 'lodash';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
import { isFetchError, reportInteraction } from '@grafana/runtime';
import { CorrelationData, isFetchError, reportInteraction } from '@grafana/runtime';
import {
Badge,
Button,
@@ -28,7 +28,7 @@ import { AddCorrelationForm } from './Forms/AddCorrelationForm';
import { EditCorrelationForm } from './Forms/EditCorrelationForm';
import { EmptyCorrelationsCTA } from './components/EmptyCorrelationsCTA';
import type { Correlation, RemoveCorrelationParams } from './types';
import { CorrelationData, useCorrelations } from './useCorrelations';
import { useCorrelations } from './useCorrelations';
const sortDatasource: SortByFn<CorrelationData> = (a, b, column) =>
a.values[column].name.localeCompare(b.values[column].name);
@@ -2,11 +2,12 @@ import { css } from '@emotion/css';
import { Controller, FieldError, useFormContext, useWatch } from 'react-hook-form';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
import { CorrelationExternal } from '@grafana/runtime';
import { Field, FieldSet, Input, Select, useStyles2 } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { CorrelationType, ExternalTypeTarget } from '../types';
import { CorrelationType } from '../types';
import { QueryEditorField } from './QueryEditorField';
import { useCorrelationsFormContext } from './correlationsFormContext';
@@ -146,7 +147,7 @@ export const ConfigureCorrelationTargetForm = () => {
},
}}
render={({ field: { onChange, value } }) => {
const castVal = value as ExternalTypeTarget; // the target under "query" type can contain anything a datasource query contains
const castVal = value as CorrelationExternal['config']['target']; // the target under "query" type can contain anything a datasource query contains
return (
<Field
label={t('correlations.target-form.target-label', 'Target')}
@@ -1,16 +1,17 @@
import { DeepMap, FieldError, FieldErrors } from 'react-hook-form';
import { SupportedTransformationType } from '@grafana/data';
import { CorrelationExternal, CorrelationQuery } from '@grafana/runtime';
import { t } from 'app/core/internationalization';
import { CorrelationConfigExternal, CorrelationConfigQuery, OmitUnion } from '../types';
import { OmitUnion } from '../types';
export interface FormExternalDTO {
sourceUID: string;
label: string;
description: string;
type: 'external';
config: CorrelationConfigExternal;
config: CorrelationExternal['config'];
}
export interface FormQueryDTO {
@@ -19,7 +20,7 @@ export interface FormQueryDTO {
label: string;
description: string;
type: 'query';
config: CorrelationConfigQuery;
config: CorrelationQuery['config'];
}
export type FormDTO = FormExternalDTO | FormQueryDTO;
+1 -35
View File
@@ -1,4 +1,4 @@
import { DataLinkTransformationConfig } from '@grafana/data';
import { CorrelationExternal, CorrelationQuery } from '@grafana/runtime';
export interface AddCorrelationResponse {
correlation: Correlation;
@@ -28,40 +28,6 @@ export interface RemoveCorrelationResponse {
export type CorrelationType = 'query' | 'external';
export type ExternalTypeTarget = { url: string };
export type CorrelationConfigQuery = {
field: string;
target: object; // for queries, this contains anything that would go in the query editor, so any extension off DataQuery a datasource would have, and needs to be generic.
transformations?: DataLinkTransformationConfig[];
};
export type CorrelationConfigExternal = {
field: string;
target: ExternalTypeTarget; // For external, this simply contains a URL
transformations?: DataLinkTransformationConfig[];
};
type CorrelationBase = {
uid: string;
sourceUID: string;
label?: string;
description?: string;
provisioned: boolean;
orgId?: number;
};
export type CorrelationExternal = CorrelationBase & {
type: 'external';
config: CorrelationConfigExternal;
};
export type CorrelationQuery = CorrelationBase & {
type: 'query';
config: CorrelationConfigQuery;
targetUID: string;
};
export type Correlation = CorrelationExternal | CorrelationQuery;
export type GetCorrelationsParams = {
@@ -1,14 +1,11 @@
import { useAsyncFn } from 'react-use';
import { lastValueFrom } from 'rxjs';
import { DataSourceInstanceSettings } from '@grafana/data';
import { getDataSourceSrv, FetchResponse } from '@grafana/runtime';
import { getDataSourceSrv, FetchResponse, CorrelationData, CorrelationsData } from '@grafana/runtime';
import { useGrafana } from 'app/core/context/GrafanaContext';
import {
Correlation,
CorrelationExternal,
CorrelationQuery,
CreateCorrelationParams,
CreateCorrelationResponse,
GetCorrelationsParams,
@@ -26,22 +23,6 @@ export interface CorrelationsResponse {
totalCount: number;
}
export type CorrelationData =
| (Omit<CorrelationExternal, 'sourceUID'> & {
source: DataSourceInstanceSettings;
})
| (Omit<CorrelationQuery, 'sourceUID' | 'targetUID'> & {
source: DataSourceInstanceSettings;
target: DataSourceInstanceSettings;
});
export interface CorrelationsData {
correlations: CorrelationData[];
page: number;
limit: number;
totalCount: number;
}
const toEnrichedCorrelationData = ({ sourceUID, ...correlation }: Correlation): CorrelationData | undefined => {
const sourceDatasource = getDataSourceSrv().getInstanceSettings(sourceUID);
const targetDatasource =
@@ -1,7 +1,6 @@
import { DataFrame, DataFrameType, DataSourceInstanceSettings, FieldType, toDataFrame } from '@grafana/data';
import { config } from '@grafana/runtime';
import { config, CorrelationData } from '@grafana/runtime';
import { CorrelationData } from './useCorrelations';
import { attachCorrelationsToDataFrames } from './utils';
describe('correlations utils', () => {
+10 -9
View File
@@ -1,20 +1,21 @@
import { lastValueFrom } from 'rxjs';
import { DataFrame, DataLinkConfigOrigin } from '@grafana/data';
import { config, createMonitoringLogger, getBackendSrv, getDataSourceSrv } from '@grafana/runtime';
import {
config,
CorrelationData,
CorrelationsData,
createMonitoringLogger,
getBackendSrv,
getDataSourceSrv,
} from '@grafana/runtime';
import { ExploreItemState } from 'app/types';
import { formatValueName } from '../explore/PrometheusListView/ItemLabels';
import { parseLogsFrame } from '../logs/logsFrame';
import { CreateCorrelationParams, CreateCorrelationResponse } from './types';
import {
CorrelationData,
CorrelationsData,
CorrelationsResponse,
getData,
toEnrichedCorrelationsData,
} from './useCorrelations';
import { CorrelationsResponse, getData, toEnrichedCorrelationsData } from './useCorrelations';
type DataFrameRefIdToDataSourceUid = Record<string, string>;
@@ -85,7 +86,7 @@ const decorateDataFrameWithInternalDataLinks = (dataFrame: DataFrame, correlatio
};
/*
If a correlation was made based on the log line field prior to the loki data plane, they would use the field "Line"
If a correlation was made based on the log line field prior to the loki data plane, they would use the field "Line"
Change it to use whatever the body field name is post-loki data plane
*/
@@ -1,11 +1,10 @@
import { Observable } from 'rxjs';
import { DataLinkTransformationConfig } from '@grafana/data';
import { getDataSourceSrv, reportInteraction } from '@grafana/runtime';
import { CorrelationData, getDataSourceSrv, reportInteraction } from '@grafana/runtime';
import { notifyApp } from 'app/core/actions';
import { createErrorNotification } from 'app/core/copy/appNotification';
import { CreateCorrelationParams } from 'app/features/correlations/types';
import { CorrelationData } from 'app/features/correlations/useCorrelations';
import { getCorrelationsBySourceUIDs, createCorrelation, generateDefaultLabel } from 'app/features/correlations/utils';
import { store } from 'app/store/store';
import { ThunkResult } from 'app/types';
@@ -11,9 +11,9 @@ import {
ExploreCorrelationHelperData,
EventBusExtended,
} from '@grafana/data';
import { CorrelationData } from '@grafana/runtime';
import { DataQuery, DataSourceRef } from '@grafana/schema';
import { getQueryKeys } from 'app/core/utils/explore';
import { CorrelationData } from 'app/features/correlations/useCorrelations';
import { getCorrelationsBySourceUIDs } from 'app/features/correlations/utils';
import { getTimeZone } from 'app/features/profile/state/selectors';
import { createAsyncThunk, ThunkResult } from 'app/types';
@@ -10,9 +10,9 @@ import {
DataSourceApi,
DataSourceInstanceSettings,
} from '@grafana/data';
import { CorrelationData } from '@grafana/runtime';
import { DataSourceJsonData, DataQuery } from '@grafana/schema';
import TableModel from 'app/core/TableModel';
import { CorrelationData } from 'app/features/correlations/useCorrelations';
import { ExplorePanelData } from 'app/types';
import {
@@ -14,12 +14,11 @@ import {
getRawDisplayProcessor,
DataSourceApi,
} from '@grafana/data';
import { config } from '@grafana/runtime';
import { config, CorrelationData } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
import { refreshIntervalToSortOrder } from '../../../core/utils/explore';
import { ExplorePanelData } from '../../../types';
import { CorrelationData } from '../../correlations/useCorrelations';
import { attachCorrelationsToDataFrames } from '../../correlations/utils';
import { dataFrameToLogsModel } from '../../logs/logsModel';
import { sortLogsResult } from '../../logs/utils';
+1 -2
View File
@@ -19,10 +19,9 @@ import {
ExploreCorrelationHelperData,
DataLinkTransformationConfig,
} from '@grafana/data';
import { CorrelationData } from '@grafana/runtime';
import { RichHistorySearchFilters, RichHistorySettings } from 'app/core/utils/richHistoryTypes';
import { CorrelationData } from '../features/correlations/useCorrelations';
export type ExploreQueryParams = UrlQueryMap;
export enum CORRELATION_EDITOR_POST_CONFIRM_ACTION {
+12 -12
View File
@@ -3151,7 +3151,7 @@ __metadata:
moment: "npm:2.30.1"
moment-timezone: "npm:0.5.46"
ol: "npm:7.4.0"
papaparse: "npm:5.4.1"
papaparse: "npm:5.5.1"
react: "npm:18.2.0"
react-dom: "npm:18.2.0"
react-use: "npm:17.6.0"
@@ -17616,7 +17616,7 @@ __metadata:
ol: "npm:7.4.0"
ol-ext: "npm:4.0.24"
pluralize: "npm:^8.0.0"
postcss: "npm:8.4.49"
postcss: "npm:8.5.1"
postcss-loader: "npm:8.1.1"
postcss-reporter: "npm:7.1.0"
postcss-scss: "npm:4.0.9"
@@ -22204,7 +22204,7 @@ __metadata:
languageName: node
linkType: hard
"nanoid@npm:^3.3.7":
"nanoid@npm:^3.3.8":
version: 3.3.8
resolution: "nanoid@npm:3.3.8"
bin:
@@ -23354,10 +23354,10 @@ __metadata:
languageName: node
linkType: hard
"papaparse@npm:5.4.1":
version: 5.4.1
resolution: "papaparse@npm:5.4.1"
checksum: 10/5e6dc978187182ad2efa1d264ffe73d2042cd23b8fb1dcb0b0f5c8c7c772c11e3eb4e166fb0893880ed24529a96abe9065d704cc5b4cb96abf037413cfe43788
"papaparse@npm:5.5.1":
version: 5.5.1
resolution: "papaparse@npm:5.5.1"
checksum: 10/6c3b47bd316cf11936641abe5590c6fb1e5b04297d1c594965a44dba89cc0f26b4e4d61eb1933352c538a30c4915d110628d14cf4d60cef0b8245c9a26477602
languageName: node
linkType: hard
@@ -24262,14 +24262,14 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:8.4.49, postcss@npm:^8.4.33, postcss@npm:^8.4.38, postcss@npm:^8.4.49":
version: 8.4.49
resolution: "postcss@npm:8.4.49"
"postcss@npm:8.5.1, postcss@npm:^8.4.33, postcss@npm:^8.4.38, postcss@npm:^8.4.49":
version: 8.5.1
resolution: "postcss@npm:8.5.1"
dependencies:
nanoid: "npm:^3.3.7"
nanoid: "npm:^3.3.8"
picocolors: "npm:^1.1.1"
source-map-js: "npm:^1.2.1"
checksum: 10/28fe1005b1339870e0a5006375ba5ac1213fd69800f79e7db09c398e074421ba6e162898e94f64942fed554037fd292db3811d87835d25ab5ef7f3c9daacb6ca
checksum: 10/1fbd28753143f7f03e4604813639918182b15343c7ad0f4e72f3875fc2cc0b8494c887f55dc05008fad5fbf1e1e908ce2edbbce364a91f84dcefb71edf7cd31d
languageName: node
linkType: hard