diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 2a190301d1d..016fb013123 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -877,3 +877,5 @@ export { userHasAllPermissions, userHasAnyPermission, } from './rbac/rbac'; + +export { type UserStorage } from './types/userStorage'; diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index d760d916f4a..d75d3f0bec4 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -19,6 +19,7 @@ import { DataQuery } from './query'; import { Scope } from './scopes'; import { AdHocVariableFilter } from './templateVars'; import { RawTimeRange, TimeRange } from './time'; +import { UserStorage } from './userStorage'; import { CustomVariableSupport, DataSourceVariableSupport, StandardVariableSupport } from './variables'; export interface DataSourcePluginOptionsEditorProps< @@ -238,6 +239,11 @@ abstract class DataSourceApi< */ interval?: string; + /** + * Initialized in datasource_srv.ts + */ + userStorage?: UserStorage; + constructor(instanceSettings: DataSourceInstanceSettings) { this.name = instanceSettings.name; this.id = instanceSettings.id; diff --git a/packages/grafana-data/src/types/userStorage.ts b/packages/grafana-data/src/types/userStorage.ts new file mode 100644 index 00000000000..e34089ee6ef --- /dev/null +++ b/packages/grafana-data/src/types/userStorage.ts @@ -0,0 +1,15 @@ +export interface UserStorage { + /** + * Retrieves an item from the backend user storage or local storage if not enabled. + * @param key - The key of the item to retrieve. + * @returns A promise that resolves to the item value or null if not found. + */ + getItem(key: string): Promise; + /** + * Sets an item in the backend user storage or local storage if not enabled. + * @param key - The key of the item to set. + * @param value - The value of the item to set. + * @returns A promise that resolves when the item is set. + */ + setItem(key: string, value: string): Promise; +} diff --git a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts index a40272f8a44..d9ed30eee0a 100644 --- a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts +++ b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts @@ -122,7 +122,7 @@ class DataSourceWithBackend< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData, > extends DataSourceApi { - protected userStorage: UserStorage; + userStorage: UserStorage; constructor(instanceSettings: DataSourceInstanceSettings) { super(instanceSettings); diff --git a/packages/grafana-runtime/src/utils/userStorage.tsx b/packages/grafana-runtime/src/utils/userStorage.tsx index 466bb5e8e7e..1bdb7cf68a2 100644 --- a/packages/grafana-runtime/src/utils/userStorage.tsx +++ b/packages/grafana-runtime/src/utils/userStorage.tsx @@ -1,7 +1,7 @@ import { get } from 'lodash'; import { lastValueFrom } from 'rxjs'; -import { usePluginContext } from '@grafana/data'; +import { usePluginContext, type UserStorage as UserStorageType } from '@grafana/data'; import { config } from '../config'; import { BackendSrvRequest, getBackendSrv } from '../services'; @@ -40,7 +40,7 @@ async function apiRequest(requestOptions: RequestOptions) { * A class for interacting with the backend user storage. * Exposed internally only to avoid misuse (wrong service name).. */ -export class UserStorage { +export class UserStorage implements UserStorageType { private service: string; private resourceName: string; private userUID: string; @@ -141,21 +141,8 @@ export class UserStorage { } } -export interface PluginUserStorage { - /** - * Retrieves an item from the backend user storage or local storage if not enabled. - * @param key - The key of the item to retrieve. - * @returns A promise that resolves to the item value or null if not found. - */ - getItem(key: string): Promise; - /** - * Sets an item in the backend user storage or local storage if not enabled. - * @param key - The key of the item to set. - * @param value - The value of the item to set. - * @returns A promise that resolves when the item is set. - */ - setItem(key: string, value: string): Promise; -} +// This is a type alias to avoid breaking changes +export interface PluginUserStorage extends UserStorageType {} /** * A hook for interacting with the backend user storage (or local storage if not enabled). diff --git a/public/app/features/plugins/datasource_srv.ts b/public/app/features/plugins/datasource_srv.ts index 4b5bcda96b8..f434681943f 100644 --- a/public/app/features/plugins/datasource_srv.ts +++ b/public/app/features/plugins/datasource_srv.ts @@ -19,7 +19,7 @@ import { TemplateSrv, isExpressionReference, } from '@grafana/runtime'; -import { ExpressionDatasourceRef } from '@grafana/runtime/internal'; +import { ExpressionDatasourceRef, UserStorage } from '@grafana/runtime/internal'; import { DataQuery, DataSourceJsonData } from '@grafana/schema'; import appEvents from 'app/core/app_events'; import config from 'app/core/config'; @@ -205,6 +205,10 @@ export class DatasourceSrv implements DataSourceService { const instance = new dsPlugin.DataSourceClass(instanceSettings); instance.components = dsPlugin.components; + if (!instance.userStorage) { + // DatasourceApi does not instantiate a userStorage property, but DataSourceWithBackend does + instance.userStorage = new UserStorage(instanceSettings.type); + } // Some old plugins does not extend DataSourceApi so we need to manually patch them if (!(instance instanceof DataSourceApi)) {