From 561156c4da99701bd95914c807a74af427e83ade Mon Sep 17 00:00:00 2001 From: "Filip \"Ret2Me\" Poplewski" <37419029+Ret2Me@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:18:14 +0100 Subject: [PATCH 01/17] Auth: Add support for the TlsSkipVerify parameter to JWT Auth (#91514) * feat(auth/JWTAuth): add support for the TlsSkipVerify parameter * feat(auth/JWTAuth): add param to default.ini and sample.ini --------- Co-authored-by: Mihaly Gyongyosi --- conf/defaults.ini | 1 + conf/sample.ini | 1 + pkg/services/auth/jwt/key_sets.go | 3 ++- pkg/setting/setting_jwt.go | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index bf0bf994b56..492151a87f2 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -937,6 +937,7 @@ auto_sign_up = false url_login = false allow_assign_grafana_admin = false skip_org_role_sync = false +tls_skip_verify_insecure = false #################################### Auth LDAP ########################### [auth.ldap] diff --git a/conf/sample.ini b/conf/sample.ini index da688f03078..f695824f04f 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -907,6 +907,7 @@ ;allow_assign_grafana_admin = false ;skip_org_role_sync = false ;signout_redirect_url = +;tls_skip_verify_insecure = false #################################### Auth LDAP ########################## [auth.ldap] diff --git a/pkg/services/auth/jwt/key_sets.go b/pkg/services/auth/jwt/key_sets.go index 5361f3b3fbb..2e5d6b22001 100644 --- a/pkg/services/auth/jwt/key_sets.go +++ b/pkg/services/auth/jwt/key_sets.go @@ -161,7 +161,8 @@ func (s *AuthService) initKeySet() error { client: &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ - Renegotiation: tls.RenegotiateFreelyAsClient, + Renegotiation: tls.RenegotiateFreelyAsClient, + InsecureSkipVerify: s.Cfg.JWTAuth.TlsSkipVerify, }, Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ diff --git a/pkg/setting/setting_jwt.go b/pkg/setting/setting_jwt.go index 42b8009de4b..2a559a145b7 100644 --- a/pkg/setting/setting_jwt.go +++ b/pkg/setting/setting_jwt.go @@ -27,6 +27,7 @@ type AuthJWTSettings struct { GroupsAttributePath string EmailAttributePath string UsernameAttributePath string + TlsSkipVerify bool } type ExtJWTSettings struct { @@ -69,6 +70,7 @@ func (cfg *Cfg) readAuthJWTSettings() { jwtSettings.GroupsAttributePath = valueAsString(authJWT, "groups_attribute_path", "") jwtSettings.EmailAttributePath = valueAsString(authJWT, "email_attribute_path", "") jwtSettings.UsernameAttributePath = valueAsString(authJWT, "username_attribute_path", "") + jwtSettings.TlsSkipVerify = authJWT.Key("tls_skip_verify_insecure").MustBool(false) cfg.JWTAuth = jwtSettings } From 28a28a686df1deeb21c037298063371cedf71f67 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 3 Mar 2025 10:19:01 +0100 Subject: [PATCH 02/17] Alerting: Fix crash when invalid matcher is used in silence query params (#101500) --- .../alerting/unified/utils/matchers.test.ts | 8 ++++++++ .../features/alerting/unified/utils/matchers.ts | 17 +++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/public/app/features/alerting/unified/utils/matchers.test.ts b/public/app/features/alerting/unified/utils/matchers.test.ts index f89e3fa8230..fdf9511c7fa 100644 --- a/public/app/features/alerting/unified/utils/matchers.test.ts +++ b/public/app/features/alerting/unified/utils/matchers.test.ts @@ -49,6 +49,14 @@ describe('Unified Alerting matchers', () => { expect(matchers[0].name).toBe('alertname'); expect(matchers[0].value).toBe('TestData 1'); }); + + it('should not crash when matcher is not valid', () => { + expect(() => { + parseQueryParamMatchers(['alertname']); + }).not.toThrow(); + + expect(parseQueryParamMatchers(['alertname'])).toHaveLength(0); + }); }); describe('normalizeMatchers', () => { diff --git a/public/app/features/alerting/unified/utils/matchers.ts b/public/app/features/alerting/unified/utils/matchers.ts index f5f5476e208..32e0f08555a 100644 --- a/public/app/features/alerting/unified/utils/matchers.ts +++ b/public/app/features/alerting/unified/utils/matchers.ts @@ -5,7 +5,7 @@ * Please keep the references to other files here to a minimum, if we reference a file that uses GrafanaBootData from `window` the worker will fail to load. */ -import { compact, uniqBy } from 'lodash'; +import { chain, compact } from 'lodash'; import { parseFlags } from '@grafana/data'; import { Matcher, MatcherOperator, ObjectMatcher, Route } from 'app/plugins/datasource/alertmanager/types'; @@ -110,11 +110,16 @@ export function parsePromQLStyleMatcherLooseSafe(matcher: string): Matcher[] { // Parses a list of entries like like "['foo=bar', 'baz=~bad*']" into SilenceMatcher[] export function parseQueryParamMatchers(matcherPairs: string[]): Matcher[] { - const parsedMatchers = matcherPairs.filter((x) => !!x.trim()).map((x) => parseMatcher(x)); - - // Due to migration, old alert rules might have a duplicated alertname label - // To handle that case want to filter out duplicates and make sure there are only unique labels - return uniqBy(parsedMatchers, (matcher) => matcher.name); + return ( + chain(matcherPairs) + .map((m) => m.trim()) // trim spaces + .compact() // remove empty strings + .flatMap(parsePromQLStyleMatcherLooseSafe) + // Due to migration, old alert rules might have a duplicated alertname label + // To handle that case want to filter out duplicates and make sure there are only unique labels + .uniqBy('name') + .value() + ); } export const getMatcherQueryParams = (labels: Labels) => { From 070d4b2ee466274a3cd145e107ab7690b0661eba Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Mon, 3 Mar 2025 11:19:17 +0100 Subject: [PATCH 03/17] SchemaV2: Accept rows with no panel property (#101503) accept rows with no panel property --- .../dashboard/api/ResponseTransformers.test.ts | 14 +++++++++++++- .../features/dashboard/api/ResponseTransformers.ts | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/api/ResponseTransformers.test.ts b/public/app/features/dashboard/api/ResponseTransformers.test.ts index 4a7a29cf711..41064867a87 100644 --- a/public/app/features/dashboard/api/ResponseTransformers.test.ts +++ b/public/app/features/dashboard/api/ResponseTransformers.test.ts @@ -406,6 +406,13 @@ describe('ResponseTransformers', () => { ], collapsed: true, }, + { + id: 6, + type: 'row', + title: 'Row with no panel property', + gridPos: { x: 0, y: 25, w: 12, h: 1 }, + collapsed: true, + }, ], }; @@ -483,7 +490,7 @@ describe('ResponseTransformers', () => { // Panel expect(spec.layout.kind).toBe('GridLayout'); const layout = spec.layout as GridLayoutKind; - expect(layout.spec.items).toHaveLength(4); + expect(layout.spec.items).toHaveLength(5); expect(layout.spec.items[0].spec).toEqual({ element: { kind: 'ElementReference', @@ -606,6 +613,11 @@ describe('ResponseTransformers', () => { height: 8, }); + const rowWithNoPanelProperty = layout.spec.items[4].spec as GridLayoutRowSpec; + expect(rowWithNoPanelProperty.collapsed).toBe(true); + expect(rowWithNoPanelProperty.title).toBe('Row with no panel property'); + expect(rowWithNoPanelProperty.elements).toHaveLength(0); + // Variables validateVariablesV1ToV2(spec.variables[0], dashboardV1.templating?.list?.[0]); validateVariablesV1ToV2(spec.variables[1], dashboardV1.templating?.list?.[1]); diff --git a/public/app/features/dashboard/api/ResponseTransformers.ts b/public/app/features/dashboard/api/ResponseTransformers.ts index 5ad1d7836d6..4dc01f06a99 100644 --- a/public/app/features/dashboard/api/ResponseTransformers.ts +++ b/public/app/features/dashboard/api/ResponseTransformers.ts @@ -298,7 +298,7 @@ function getElementsFromPanels( const rowElements = []; - for (const panel of p.panels) { + for (const panel of p.panels || []) { const [element, name] = buildElement(panel); elements[name] = element; rowElements.push(buildGridItemKind(panel, name, yOffsetInRows(panel, p.gridPos!.y))); From d3b550c230ccf9118880865e97b5d640c20afbf1 Mon Sep 17 00:00:00 2001 From: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:49:32 +0000 Subject: [PATCH 04/17] Dashboards: Redesign edit pane of dashboard and viz panels (#101437) * adjust options pane category component and shared logic * redesign dashboard edit pane * clean up * redesign viz panel edit panes * address comments * updated i18n * clean up * address comments --- .../edit-pane/DashboardEditableElement.tsx | 24 ++-- .../edit-pane/EditPaneHeader.tsx | 57 ++++++++ .../edit-pane/ElementEditPane.tsx | 2 + .../MultiSelectedVizPanelsEditableElement.tsx | 40 +++--- .../edit-pane/VizPanelEditableElement.tsx | 136 +++++++++++------- .../DashboardLayoutSelector.tsx | 7 +- .../scene/types/EditableDashboardElement.ts | 10 ++ .../MultiSelectedEditableDashboardElement.ts | 10 ++ .../PanelEditor/OptionsPaneCategory.tsx | 42 ++++-- .../OptionsPaneCategoryDescriptor.tsx | 1 + public/locales/en-US/grafana.json | 19 ++- public/locales/pseudo-LOCALE/grafana.json | 19 ++- 12 files changed, 252 insertions(+), 115 deletions(-) create mode 100644 public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx index 77255075393..ae3085bc055 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx @@ -6,7 +6,7 @@ import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor'; import { DashboardScene } from '../scene/DashboardScene'; -import { useLayoutCategory } from '../scene/layouts-shared/DashboardLayoutSelector'; +import { DashboardLayoutSelector } from '../scene/layouts-shared/DashboardLayoutSelector'; import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; export class DashboardEditableElement implements EditableDashboardElement { @@ -28,29 +28,29 @@ export class DashboardEditableElement implements EditableDashboardElement { return new OptionsPaneCategoryDescriptor({ title: t('dashboard.options.title', 'Dashboard options'), id: 'dashboard-options', - isOpenDefault: true, + isOpenable: false, }) .addItem( new OptionsPaneItemDescriptor({ title: t('dashboard.options.title-option', 'Title'), - render: function renderTitle() { - return ; - }, + render: () => , }) ) .addItem( new OptionsPaneItemDescriptor({ title: t('dashboard.options.description', 'Description'), - render: function renderTitle() { - return ; - }, + render: () => , + }) + ) + .addItem( + new OptionsPaneItemDescriptor({ + title: t('dashboard.layout.common.layout', 'Layout'), + render: () => , }) ); - }, [dashboard]); + }, [body, dashboard]); - const layoutCategory = useLayoutCategory(body); - - return [dashboardOptions, layoutCategory]; + return [dashboardOptions]; } } diff --git a/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx new file mode 100644 index 00000000000..653daf384f2 --- /dev/null +++ b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx @@ -0,0 +1,57 @@ +import { Dropdown, Button, IconButton, Menu, Stack, Icon } from '@grafana/ui'; +import { t } from 'app/core/internationalization'; + +interface EditPaneHeaderProps { + title: string; + onDelete?: () => void; + onCopy?: () => void; + onDuplicate?: () => void; +} + +export const EditPaneHeader = ({ title, onDelete, onCopy, onDuplicate }: EditPaneHeaderProps) => { + const addCopyOrDuplicate = onCopy || onDuplicate; + return ( + + {title} + + {addCopyOrDuplicate ? ( + }> + + + ) : null} + + + + + ); +}; + +type MenuItemsProps = { + onCopy?: () => void; + onDuplicate?: () => void; +}; + +const MenuItems = ({ onCopy, onDuplicate }: MenuItemsProps) => { + return ( + + {onCopy ? : null} + {onDuplicate ? ( + + ) : null} + + ); +}; diff --git a/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx b/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx index 47cd84ade4b..01b9a3f2398 100644 --- a/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx +++ b/public/app/features/dashboard-scene/edit-pane/ElementEditPane.tsx @@ -24,6 +24,8 @@ export function ElementEditPane({ element }: Props) { title={elementInfo.name} isOpenDefault={true} className={styles.noBorderTop} + renderTitle={element.renderTitle} + isOpenable={element.isOpenable} >
{element.renderActions()}
diff --git a/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx index afa29772adc..3e6a7fa98ae 100644 --- a/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx +++ b/public/app/features/dashboard-scene/edit-pane/MultiSelectedVizPanelsEditableElement.tsx @@ -1,14 +1,15 @@ -import { ReactNode } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { VizPanel } from '@grafana/scenes'; -import { Button, Stack, Text } from '@grafana/ui'; -import { t, Trans } from 'app/core/internationalization'; +import { t } from 'app/core/internationalization'; +import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor'; import { EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement'; import { MultiSelectedEditableDashboardElement } from '../scene/types/MultiSelectedEditableDashboardElement'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; +import { EditPaneHeader } from './EditPaneHeader'; + export class MultiSelectedVizPanelsEditableElement implements MultiSelectedEditableDashboardElement { public readonly isMultiSelectedEditableDashboardElement = true; public readonly key: string; @@ -21,23 +22,22 @@ export class MultiSelectedVizPanelsEditableElement implements MultiSelectedEdita return { name: t('dashboard.edit-pane.elements.panels', 'Panels'), typeId: 'panels', icon: 'folder' }; } - renderActions(): ReactNode { - return ( - - - - No. of panels selected: {{ length }} - - - - -