diff --git a/grafana/rmf-app/CHANGELOG.md b/grafana/rmf-app/CHANGELOG.md index 14e0706..2920389 100644 --- a/grafana/rmf-app/CHANGELOG.md +++ b/grafana/rmf-app/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## 2.0.0.1 (2026-06-26) +- Add Grafana v13 support. + ## 2.0.0 (2026-03-06) - You can now import RMF Performance Monitoring dashboards and their associated data sources directly into Grafana for visualization. - The custom RMF full report panel (ibm-rmf-panel) has been deprecated and removed. Full RMF reports now rely on standard Grafana visualizations. diff --git a/grafana/rmf-app/src/datasource/datasource.ts b/grafana/rmf-app/src/datasource/datasource.ts index bbe086d..ab8f42d 100644 --- a/grafana/rmf-app/src/datasource/datasource.ts +++ b/grafana/rmf-app/src/datasource/datasource.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import { DataSourceInstanceSettings, MetricFindValue, ScopedVars } from '@grafana/data'; -import { DataSourceWithBackend, getBackendSrv, getTemplateSrv } from '@grafana/runtime'; +import { DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime'; import { getResourceName, queryValidation } from './common/common.helper'; import { RMFDataSourceJsonData, RMFQuery, resourceBaseData } from './common/types'; @@ -71,74 +71,46 @@ export class DataSource extends DataSourceWithBackend { - const metricFindValue = this.loadDataFromService(resourceString, id, options) - .then((resp: any) => { - const result = JSON.parse(resp.data); - let resNames = getResourceName(result); - const retResult: MetricFindValue[] = []; - resNames.map((row: any, index: number) => { - let itemName = ''; - try { - // itemName = row[queryResult.columnName.toLowerCase()][0].trim(); - itemName = row[queryResult.columnName.toLowerCase()].trim(); - let itemNameParts = itemName.split(','); - if (itemNameParts[1].trim() === '*') { - itemName = itemNameParts[2].trim(); // Ex: ULQ01,*,ALL_WLM_RESOURCE_GROUPS - } else { - itemName = itemNameParts[1].trim(); // Ex: ULQ01,BATCHLOW,WLM_RESOURCE_GROUP - } - if ( - queryResult.filterTypes.trim() !== '' && - queryResult.filterTypes.indexOf(row.restype.toUpperCase().trim()) !== -1 - ) { - retResult.push({ text: itemName }); - } else if (queryResult.filterTypes.trim() === '') { - retResult.push({ text: itemName }); - } - } catch (errorObj) {} - }); - return retResult; - }) - .catch((err) => { - throw new Error(err.message + ', [resource=' + queryResult.resourceCommand + ']'); - }); - return resolve(metricFindValue); - }); - } + try { + const data = await this.postResource('variablequery', JSON.stringify({ query: resourceString }), { + headers: { + Accept: 'application/text', + 'Content-Type': 'application/text', + }, + responseType: 'text', + }); + + if (!data) { + throw new Error('Test connection failed.'); + } - async loadDataFromService(urlPath: string, id?: number, options?: any) { - return new Promise((resolve, reject) => - getBackendSrv() - .fetch({ - method: 'post', - headers: { - Accept: 'application/text', - 'Content-Type': 'application/text', - }, - url: `/api/datasources/${id}/resources/variablequery`, - responseType: 'text', - data: JSON.stringify({ query: urlPath }), - }) - .subscribe( - (resp) => { - if (resp.data) { - if (options !== undefined && options === 'headres') { - } else { - resolve({ - data: resp.data, - }); - } - } else { - reject({ status: 'failure', message: 'Test connection failed.' }); - } - }, - (err) => { - reject({ status: 'failure', message: err.data.message }); + const result = JSON.parse(data as string); + let resNames = getResourceName(result); + const retResult: MetricFindValue[] = []; + resNames.map((row: any, index: number) => { + let itemName = ''; + try { + itemName = row[queryResult.columnName.toLowerCase()].trim(); + let itemNameParts = itemName.split(','); + if (itemNameParts[1].trim() === '*') { + itemName = itemNameParts[2].trim(); // Ex: ULQ01,*,ALL_WLM_RESOURCE_GROUPS + } else { + itemName = itemNameParts[1].trim(); // Ex: ULQ01,BATCHLOW,WLM_RESOURCE_GROUP } - ) - ); + if ( + queryResult.filterTypes.trim() !== '' && + queryResult.filterTypes.indexOf(row.restype.toUpperCase().trim()) !== -1 + ) { + retResult.push({ text: itemName }); + } else if (queryResult.filterTypes.trim() === '') { + retResult.push({ text: itemName }); + } + } catch (errorObj) {} + }); + return retResult; + } catch (err: any) { + throw new Error((err.message || err.data?.message) + ', [resource=' + queryResult.resourceCommand + ']'); + } } } diff --git a/grafana/rmf-app/src/datasource/query-editor/queryeditor.parser.component.tsx b/grafana/rmf-app/src/datasource/query-editor/queryeditor.parser.component.tsx index 82f41ad..dbc9fe4 100644 --- a/grafana/rmf-app/src/datasource/query-editor/queryeditor.parser.component.tsx +++ b/grafana/rmf-app/src/datasource/query-editor/queryeditor.parser.component.tsx @@ -17,7 +17,7 @@ // import defaults from 'lodash/defaults'; import { QueryEditorProps } from '@grafana/data'; -import { getBackendSrv, getTemplateSrv } from '@grafana/runtime'; +import { getTemplateSrv } from '@grafana/runtime'; import { RadioButtonGroup, Spinner, Switch } from '@grafana/ui'; import React, { PureComponent } from 'react'; import { AutocompleteTextField } from '../autocomplete-text/autocomplete-textfield'; @@ -80,13 +80,6 @@ export class QueryEditorAutoCompleteComponent extends PureComponent {}) - .catch((err: any) => { - this.setServiceCallInprogresState(false); - }); - } } componentDidMount() { @@ -95,37 +88,37 @@ export class QueryEditorAutoCompleteComponent extends PureComponent {}) + .catch((err: any) => { + this.setServiceCallInprogresState(false); + }); + } } - async loadDataFromService(id: number) { - return await new Promise((resolve, reject) => - getBackendSrv() - .fetch({ - method: 'post', - headers: { - Accept: 'application/text', - 'Content-Type': 'application/text', - }, - url: `/api/datasources/${id}/resources/autopopulate`, - responseType: 'text', - }) - .subscribe( - (resp) => { - if (resp.data) { - let result = JSON.parse(resp.data as string); - let resourceList: any[] = getResource(result); - metricDict = loadDataToDictionary(resourceList); - resolve(true); - } else { - reject(false); - } - }, - (err) => { - this.setServiceCallInprogresState(false); - reject(false); - } - ) - ); + async loadMetricsIndex() { + try { + const data = await this.props.datasource.postResource('autopopulate', undefined, { + headers: { + Accept: 'application/text', + 'Content-Type': 'application/text', + }, + responseType: 'text', + }); + + if (data) { + let result = JSON.parse(data as string); + let resourceList: any[] = getResource(result); + metricDict = loadDataToDictionary(resourceList); + return true; + } else { + return Promise.reject(false); + } + } catch (err) { + this.setServiceCallInprogresState(false); + return Promise.reject(false); + } } onTextChange = (val: string, e: any) => {