/usr/share/grafana/public/app/plugins/datasource/azuremonitor/components/ResourcePicker
import { produce } from 'immer'; import { getTemplateSrv } from '@grafana/runtime'; import UrlBuilder from '../../azure_monitor/url_builder'; import { ResourcePickerQueryType } from '../../resourcePicker/resourcePickerData'; import { AzureMonitorQuery, AzureMonitorResource } from '../../types/query'; import { ResourceRow, ResourceRowGroup } from './types'; // This regex matches URIs representing: // - subscriptions: /subscriptions/44693801-6ee6-49de-9b2d-9106972f9572 // - resource groups: /subscriptions/44693801-6ee6-49de-9b2d-9106972f9572/resourceGroups/cloud-datasources // - resources: /subscriptions/44693801-6ee6-49de-9b2d-9106972f9572/resourceGroups/cloud-datasources/providers/Microsoft.Compute/virtualMachines/GithubTestDataVM const RESOURCE_URI_REGEX = /\/subscriptions\/(?<subscription>[^/]+)(?:\/resourceGroups\/(?<resourceGroup>[^/]+)(?:\/providers\/(?<metricNamespaceAndResource>.+))?)?/i; type RegexGroups = Record<string, string | undefined>; function parseNamespaceAndName(metricNamespaceAndName?: string) { if (!metricNamespaceAndName) { return {}; } const stringArray = metricNamespaceAndName.split('/'); // The first two groups belong to the namespace (e.g. Microsoft.Storage/storageAccounts) const namespaceArray = stringArray.splice(0, 2); // The next element belong to the resource name (e.g. storageAcc1) const resourceNameArray = stringArray.splice(0, 1); // If there are more elements, keep adding them to the namespace and resource name, alternatively // e.g (blobServices/default) while (stringArray.length) { const nextElem = stringArray.shift()!; stringArray.length % 2 === 0 ? resourceNameArray.push(nextElem) : namespaceArray.push(nextElem); } return { metricNamespace: namespaceArray.join('/'), resourceName: resourceNameArray.join('/') }; } export function parseResourceURI(resourceURI: string): AzureMonitorResource { const matches = RESOURCE_URI_REGEX.exec(resourceURI); const groups: RegexGroups = matches?.groups ?? {}; const { subscription, resourceGroup, metricNamespaceAndResource } = groups; const { metricNamespace, resourceName } = parseNamespaceAndName(metricNamespaceAndResource); return { subscription, resourceGroup, metricNamespace, resourceName }; } export function parseMultipleResourceDetails(resources: Array<string | AzureMonitorResource>, location?: string) { return resources.map((resource) => { return parseResourceDetails(resource, location); }); } export function parseResourceDetails(resource: string | AzureMonitorResource, location?: string) { if (typeof resource === 'string') { const res = parseResourceURI(resource); if (location) { res.region = location; } return res; } return resource; } export function resourcesToStrings(resources: Array<string | AzureMonitorResource>) { return resources.map((resource) => resourceToString(resource)); } export function resourceToString(resource?: string | AzureMonitorResource) { return resource ? typeof resource === 'string' ? resource : UrlBuilder.buildResourceUri(getTemplateSrv(), resource) : ''; } export function isGUIDish(input: string) { return !!input.match(/^[A-Z0-9]+/i); } function compareNamespaceAndName( rowNamespace?: string, rowName?: string, resourceNamespace?: string, resourceName?: string ) { // StorageAccounts subresources are not listed independently if (resourceNamespace?.startsWith('microsoft.storage/storageaccounts')) { resourceNamespace = 'microsoft.storage/storageaccounts'; if (resourceName?.endsWith('/default')) { resourceName = resourceName.slice(0, -'/default'.length); } } return rowNamespace === resourceNamespace && rowName === resourceName; } export function matchURI(rowURI: string, resourceURI: string) { const targetParams = parseResourceDetails(resourceURI); const rowParams = parseResourceDetails(rowURI); return ( rowParams?.subscription === targetParams?.subscription && rowParams?.resourceGroup?.toLowerCase() === targetParams?.resourceGroup?.toLowerCase() && compareNamespaceAndName( rowParams?.metricNamespace?.toLowerCase(), rowParams?.resourceName, targetParams?.metricNamespace?.toLowerCase(), targetParams?.resourceName ) ); } export function findRows(rows: ResourceRowGroup, uris: string[]): ResourceRow[] { const result: ResourceRow[] = []; uris.forEach((uri) => { const row = findRow(rows, uri); if (row) { result.push(row); } }); return result; } export function findRow(rows: ResourceRowGroup, uri: string): ResourceRow | undefined { for (const row of rows) { if (matchURI(row.uri, uri)) { return row; } if (row.children) { const result = findRow(row.children, uri); if (result) { return result; } } } return undefined; } export function addResources(rows: ResourceRowGroup, targetParentId: string, newResources: ResourceRowGroup) { return produce(rows, (draftState) => { const draftRow = findRow(draftState, targetParentId); // we can't find the selected resource in our list of resources, // probably means user has either mistyped in the input field // or is using template variables. // either way no need to throw, just show that none of the resources are checked if (!draftRow) { return; } draftRow.children = newResources; }); } export function setResources( query: AzureMonitorQuery, type: ResourcePickerQueryType, resources: Array<string | AzureMonitorResource> ): AzureMonitorQuery { if (type === 'logs') { // Resource URI for LogAnalytics return { ...query, azureLogAnalytics: { ...query.azureLogAnalytics, resources: resourcesToStrings(resources).filter((resource) => resource !== ''), }, }; } if (type === 'traces') { // Resource URI for Traces return { ...query, azureTraces: { ...query.azureTraces, resources: resourcesToStrings(resources).filter((resource) => resource !== ''), }, }; } // Resource object for metrics const parsedResource = resources.length ? parseResourceDetails(resources[0]) : {}; return { ...query, subscription: parsedResource.subscription, azureMonitor: { ...query.azureMonitor, metricNamespace: parsedResource.metricNamespace?.toLocaleLowerCase(), region: parsedResource.region, resources: parseMultipleResourceDetails(resources).filter( (resource) => resource.resourceName !== '' && resource.metricNamespace !== '' && resource.subscription !== '' && resource.resourceGroup !== '' ), metricName: undefined, aggregation: undefined, timeGrain: '', dimensionFilters: [], }, }; }
.
Edit
..
Edit
AdvancedMulti.test.tsx
Edit
AdvancedMulti.tsx
Edit
EntryIcon.tsx
Edit
NestedEntry.test.tsx
Edit
NestedEntry.tsx
Edit
NestedRow.test.tsx
Edit
NestedRow.tsx
Edit
ResourcePicker.test.tsx
Edit
ResourcePicker.tsx
Edit
Search.tsx
Edit
styles.ts
Edit
types.ts
Edit
utils.test.ts
Edit
utils.ts
Edit