From 0a6d78f35e1a12f4c8110f227118d926b5a34db3 Mon Sep 17 00:00:00 2001 From: Alyssa Bull <58453566+alyssabull@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:42:01 -0600 Subject: [PATCH] AzureMonitor: Azure Monitor Cheat sheet (#75931) --- .../azure_log_analytics_datasource.ts | 4 + .../components/AzureCheatSheet.tsx | 263 +++++++++++++ .../LogsQueryEditor/AzureCheatSheetModal.tsx | 34 ++ .../components/QueryEditor/QueryEditor.tsx | 34 +- .../azuremonitor/components/RawQuery.tsx | 37 ++ .../azuremonitor/components/syntax.ts | 366 ++++++++++++++++++ .../datasource/azuremonitor/types/types.ts | 38 ++ 7 files changed, 773 insertions(+), 3 deletions(-) create mode 100644 public/app/plugins/datasource/azuremonitor/components/AzureCheatSheet.tsx create mode 100644 public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheetModal.tsx create mode 100644 public/app/plugins/datasource/azuremonitor/components/RawQuery.tsx create mode 100644 public/app/plugins/datasource/azuremonitor/components/syntax.ts diff --git a/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts b/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts index 827bd8ce1ba..bf035aed1d8 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_log_analytics/azure_log_analytics_datasource.ts @@ -248,4 +248,8 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< private isValidConfigField(field: string | undefined): boolean { return typeof field === 'string' && field.length > 0; } + + async getAzureLogAnalyticsCheatsheetQueries() { + return await this.getResource(`${this.resourcePath}/v1/metadata`); + } } diff --git a/public/app/plugins/datasource/azuremonitor/components/AzureCheatSheet.tsx b/public/app/plugins/datasource/azuremonitor/components/AzureCheatSheet.tsx new file mode 100644 index 00000000000..7611ad31c92 --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/components/AzureCheatSheet.tsx @@ -0,0 +1,263 @@ +import { css } from '@emotion/css'; +import React, { useEffect, useMemo, useState } from 'react'; + +import { GrafanaTheme2, SelectableValue } from '@grafana/data'; +import { reportInteraction } from '@grafana/runtime'; +import { + Button, + Card, + Collapse, + CustomScrollbar, + Field, + Input, + LoadingPlaceholder, + Select, + useStyles2, +} from '@grafana/ui'; + +import AzureLogAnalyticsDatasource from '../azure_log_analytics/azure_log_analytics_datasource'; +import { + AzureMonitorQuery, + AzureQueryType, + Category, + CheatsheetQueries, + CheatsheetQuery, + DropdownCategories, +} from '../types'; + +import { RawQuery } from './RawQuery'; +import tokenizer from './syntax'; + +export interface AzureCheatSheetProps { + onChange: (query: AzureMonitorQuery) => void; + query: AzureMonitorQuery; + datasource: AzureLogAnalyticsDatasource; +} + +const AzureCheatSheet = (props: AzureCheatSheetProps) => { + const [cheatsheetQueries, setCheatsheetQueries] = useState(null); + const [areDropdownsOpen, setAreDropdownsOpen] = useState({}); + const [visibleQueries, setVisibleQueries] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [searchInputValue, setSearchInputValue] = useState(''); + const styles = useStyles2(getStyles); + const lang = { grammar: tokenizer, name: 'kql' }; + const dropdownMenu = useMemo(() => { + if (cheatsheetQueries) { + return Object.keys(cheatsheetQueries).map((category): SelectableValue => { + return { + label: category, + value: category, + }; + }); + } + return []; + }, [cheatsheetQueries]); + + const getCheatsheetQueries = async () => { + await props.datasource.getAzureLogAnalyticsCheatsheetQueries().then((result) => { + result.categories.sort((a: Category, b: Category) => { + return a.displayName.toLowerCase() === b.displayName.toLowerCase() + ? 0 + : a.displayName.toLowerCase() < b.displayName.toLowerCase() + ? -1 + : 1; + }); + const alphabetizedQueries = result.categories.reduce( + (queriesByCategory: CheatsheetQueries, category: Category) => { + const categoryQueries = category.related.queries.map((queryId: string) => { + return result.queries.find((query: CheatsheetQuery) => query.id === queryId); + }); + queriesByCategory[category.displayName] = categoryQueries; + setAreDropdownsOpen({ ...areDropdownsOpen, [category.id]: false }); + return queriesByCategory; + }, + {} + ); + setCheatsheetQueries(alphabetizedQueries); + setVisibleQueries(alphabetizedQueries); + setIsLoading(false); + return alphabetizedQueries; + }); + }; + + useEffect(() => { + if (!cheatsheetQueries) { + getCheatsheetQueries(); + } + }); + + const filterQueriesBySearch = (searchValue: string) => { + const visibleQueriesCategories = Object.keys(visibleQueries!); + if (searchValue.length > 0 && cheatsheetQueries) { + const filteredQueries: CheatsheetQueries = Object.keys(cheatsheetQueries).reduce( + (filteredQueriesBySearch: CheatsheetQueries, category) => { + const filters = cheatsheetQueries![category]!.filter((query) => { + return query.displayName.toLowerCase().includes(searchValue.toLowerCase()); + }); + if (visibleQueriesCategories.includes(category)) { + filteredQueriesBySearch[category] = filters; + } + return filteredQueriesBySearch; + }, + {} + ); + + setVisibleQueries(filteredQueries); + return filteredQueries; + } else { + if (Object.keys(visibleQueries!).length !== Object.keys(cheatsheetQueries!).length) { + setVisibleQueries(visibleQueries); + return visibleQueries; + } else { + setVisibleQueries(cheatsheetQueries); + return cheatsheetQueries; + } + } + }; + + const filterQueriesByCategory = (categories: SelectableValue) => { + if (categories.length > 0) { + const selectedCategories = categories.map((selectedCategory: SelectableValue) => selectedCategory.label); + const updatedVisibleQueries = selectedCategories.reduce( + (updatedVisibleQueries: CheatsheetQueries, queryCategory: string) => { + updatedVisibleQueries[queryCategory] = cheatsheetQueries![queryCategory]!; + return updatedVisibleQueries; + }, + {} + ); + setVisibleQueries(updatedVisibleQueries); + } else { + setVisibleQueries(cheatsheetQueries); + } + }; + + return ( +
+ {!isLoading && visibleQueries ? ( +
+
+ { + setSearchInputValue(e.currentTarget.value); + const filteredQueries = filterQueriesBySearch(e.currentTarget.value); + setVisibleQueries(filteredQueries); + }} + placeholder="Search Logs queries" + width={40} + /> + +