User Storage: Expose functionality for frontend-only datasources (#106165)

This commit is contained in:
Andres Martinez Gotor
2025-05-29 14:44:00 +02:00
committed by GitHub
parent fc988c8771
commit 301d78bf96
6 changed files with 33 additions and 19 deletions
+2
View File
@@ -877,3 +877,5 @@ export {
userHasAllPermissions,
userHasAnyPermission,
} from './rbac/rbac';
export { type UserStorage } from './types/userStorage';
@@ -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<TOptions>) {
this.name = instanceSettings.name;
this.id = instanceSettings.id;
@@ -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<string | null>;
/**
* 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<void>;
}
@@ -122,7 +122,7 @@ class DataSourceWithBackend<
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData,
> extends DataSourceApi<TQuery, TOptions> {
protected userStorage: UserStorage;
userStorage: UserStorage;
constructor(instanceSettings: DataSourceInstanceSettings<TOptions>) {
super(instanceSettings);
@@ -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<T>(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<string | null>;
/**
* 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<void>;
}
// 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).
@@ -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)) {