mirror of https://github.com/grafana/grafana.git
				
				
				
			Merge branch 'main' into drclau/unistor/replace-authenticators-3
This commit is contained in:
		
						commit
						a6c977ba4d
					
				|  | @ -2750,9 +2750,6 @@ exports[`better eslint`] = { | |||
|     "public/app/features/dashboard-scene/saving/shared.tsx:5381": [ | ||||
|       [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"] | ||||
|     ], | ||||
|     "public/app/features/dashboard-scene/scene/DashboardControls.tsx:5381": [ | ||||
|       [0, 0, 0, "Do not use any type assertions.", "0"] | ||||
|     ], | ||||
|     "public/app/features/dashboard-scene/scene/NavToolbarActions.tsx:5381": [ | ||||
|       [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"], | ||||
|       [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"], | ||||
|  |  | |||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -26,7 +26,7 @@ plugins: | |||
|   - path: .yarn/plugins/@yarnpkg/plugin-outdated.cjs | ||||
|     spec: 'https://mskelton.dev/yarn-outdated/v2' | ||||
| 
 | ||||
| yarnPath: .yarn/releases/yarn-4.4.1.cjs | ||||
| yarnPath: .yarn/releases/yarn-4.5.0.cjs | ||||
| # Uncomment the following lines if you want to use Verdaccio local npm registry. Read more at packages/README.md | ||||
| #npmScopes: | ||||
| # grafana: | ||||
|  |  | |||
|  | @ -912,10 +912,10 @@ Content-Type: application/json | |||
|          "datasource":{ | ||||
|             "uid":"PD8C576611E62080A" | ||||
|          }, | ||||
|          "format": "table" | ||||
|          "format": "table", | ||||
|          "maxDataPoints":1848, | ||||
|          "intervalMs":200, | ||||
|          "stringInput":"1,20,90,30,5,0", | ||||
|          "stringInput":"1,20,90,30,5,0" | ||||
|       } | ||||
|    ], | ||||
|    "from":"now-5m", | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ describe('Dashboards', () => { | |||
|     e2e.components.Panels.Panel.title('Panel #1').should('be.visible'); | ||||
| 
 | ||||
|     // scroll to the bottom
 | ||||
|     cy.get('#page-scrollbar').scrollTo('bottom', { | ||||
|     cy.scrollTo('bottom', { | ||||
|       timeout: 5 * 1000, | ||||
|     }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ describe('Dashboards', () => { | |||
|     e2e.components.Panels.Panel.title('Panel #1').should('be.visible'); | ||||
| 
 | ||||
|     // scroll to the bottom
 | ||||
|     cy.get('#page-scrollbar').scrollTo('bottom', { | ||||
|     cy.scrollTo('bottom', { | ||||
|       timeout: 5 * 1000, | ||||
|     }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ describe('Auto-migrate graph panel', () => { | |||
|         e2e.pages.Dashboard.Annotations.marker().should('exist'); | ||||
|       }); | ||||
| 
 | ||||
|     cy.get('#pageContent .scrollbar-view').first().scrollTo('bottom'); | ||||
|     cy.scrollTo('bottom'); | ||||
| 
 | ||||
|     e2e.components.Panels.Panel.title('05:00') | ||||
|       .should('exist') | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ describe('Auto-migrate graph panel', () => { | |||
|         e2e.pages.Dashboard.Annotations.marker().should('exist'); | ||||
|       }); | ||||
| 
 | ||||
|     cy.get('#pageContent .scrollbar-view').first().scrollTo('bottom'); | ||||
|     cy.scrollTo('bottom'); | ||||
| 
 | ||||
|     e2e.components.Panels.Panel.title('05:00') | ||||
|       .should('exist') | ||||
|  |  | |||
							
								
								
									
										2
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										2
									
								
								go.mod
								
								
								
								
							|  | @ -74,7 +74,7 @@ require ( | |||
| 	github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group | ||||
| 	github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad | ||||
| 	github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10 // @grafana/alerting-backend | ||||
| 	github.com/grafana/authlib v0.0.0-20240827201526-24af227df935 // @grafana/identity-access-team | ||||
| 	github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 // @grafana/identity-access-team | ||||
| 	github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd // @grafana/identity-access-team | ||||
| 	github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad | ||||
| 	github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										4
									
								
								go.sum
								
								
								
								
							|  | @ -2258,8 +2258,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm | |||
| github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||
| github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10 h1:oDbLKM34O+JUF9EQFS+9aYhdYoeNfUpXqNjFCLIxwF4= | ||||
| github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4= | ||||
| github.com/grafana/authlib v0.0.0-20240827201526-24af227df935 h1:nT4UY61s2flsiLkU2jDqtqFhOLwqh355+8ZhnavKoMQ= | ||||
| github.com/grafana/authlib v0.0.0-20240827201526-24af227df935/go.mod h1:ER7bMzNNWTN/5Zl3pwqfgS6XEhcanjrvL7lOp8Ow6oc= | ||||
| github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 h1:zYF/RBulpvMqPYR3gbzJZ8t/j/Eymn5FNidSYkueNCA= | ||||
| github.com/grafana/authlib v0.0.0-20240919120951-58259833c564/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY= | ||||
| github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd h1:sIlR7n38/MnZvX2qxDEszywXdI5soCwQ78aTDSARvus= | ||||
| github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A= | ||||
| github.com/grafana/codejen v0.0.3 h1:tAWxoTUuhgmEqxJPOLtJoxlPBbMULFwKFOcRsPRPXDw= | ||||
|  |  | |||
|  | @ -119,10 +119,10 @@ | |||
|     "@types/jquery": "3.5.30", | ||||
|     "@types/js-yaml": "^4.0.5", | ||||
|     "@types/jsurl": "^1.2.28", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/logfmt": "^1.2.3", | ||||
|     "@types/lucene": "^2", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/node-forge": "^1", | ||||
|     "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@3.2.4", | ||||
|     "@types/pluralize": "^0.0.33", | ||||
|  | @ -249,7 +249,7 @@ | |||
|     "@emotion/css": "11.11.2", | ||||
|     "@emotion/react": "11.11.4", | ||||
|     "@fingerprintjs/fingerprintjs": "^3.4.2", | ||||
|     "@floating-ui/react": "0.26.23", | ||||
|     "@floating-ui/react": "0.26.24", | ||||
|     "@formatjs/intl-durationformat": "^0.2.4", | ||||
|     "@glideapps/glide-data-grid": "^6.0.0", | ||||
|     "@grafana/aws-sdk": "0.4.2", | ||||
|  | @ -440,7 +440,7 @@ | |||
|   "engines": { | ||||
|     "node": ">= 20" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1", | ||||
|   "packageManager": "yarn@4.5.0", | ||||
|   "dependenciesMeta": { | ||||
|     "prettier@3.3.3": { | ||||
|       "unplugged": true | ||||
|  |  | |||
|  | @ -65,8 +65,8 @@ | |||
|     "@rollup/plugin-node-resolve": "15.2.4", | ||||
|     "@types/dompurify": "^3.0.0", | ||||
|     "@types/history": "4.7.11", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/papaparse": "5.3.14", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|  |  | |||
|  | @ -309,6 +309,63 @@ describe('applyFieldOverrides', () => { | |||
|     expect(config.decimals).toEqual(1); | ||||
|   }); | ||||
| 
 | ||||
|   it('displayName should be able to reference itself', () => { | ||||
|     const data = applyFieldOverrides({ | ||||
|       data: [f0], // the frame
 | ||||
|       fieldConfig: { | ||||
|         defaults: { | ||||
|           displayName: '${__field.displayName} and more!', | ||||
|         }, | ||||
|         overrides: [], | ||||
|       }, | ||||
|       replaceVariables: (v, scopedVars) => { | ||||
|         const dataContext = scopedVars?.__dataContext?.value; | ||||
|         if (dataContext) { | ||||
|           // Trying to fake what would happen with the real interpolation function
 | ||||
|           return getFieldDisplayName(dataContext.field, dataContext.frame) + ' and more!'; | ||||
|         } | ||||
|         return v; | ||||
|       }, | ||||
|       theme: createTheme(), | ||||
|       fieldConfigRegistry: customFieldRegistry, | ||||
|     })[0]; | ||||
| 
 | ||||
|     const valueColumn = data.fields[1]; | ||||
|     const displayName = getFieldDisplayName(valueColumn, data); | ||||
| 
 | ||||
|     expect(displayName).toEqual('value and more!'); | ||||
|   }); | ||||
| 
 | ||||
|   it('displayName should be able to reference itself in an override', () => { | ||||
|     const data = applyFieldOverrides({ | ||||
|       data: [f0], // the frame
 | ||||
|       fieldConfig: { | ||||
|         defaults: {}, | ||||
|         overrides: [ | ||||
|           { | ||||
|             matcher: { id: FieldMatcherID.byName, options: 'value' }, | ||||
|             properties: [{ id: 'displayName', value: '${__field.displayName} and more!' }], | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       replaceVariables: (v, scopedVars) => { | ||||
|         const dataContext = scopedVars?.__dataContext?.value; | ||||
|         if (dataContext) { | ||||
|           // Trying to fake what would happen with the real interpolation function
 | ||||
|           return getFieldDisplayName(dataContext.field, dataContext.frame) + ' and more!'; | ||||
|         } | ||||
|         return v; | ||||
|       }, | ||||
|       theme: createTheme(), | ||||
|       fieldConfigRegistry: customFieldRegistry, | ||||
|     })[0]; | ||||
| 
 | ||||
|     const valueColumn = data.fields[1]; | ||||
|     const displayName = getFieldDisplayName(valueColumn, data); | ||||
| 
 | ||||
|     expect(displayName).toEqual('value and more!'); | ||||
|   }); | ||||
| 
 | ||||
|   it('will apply set min/max when asked', () => { | ||||
|     const data = applyFieldOverrides({ | ||||
|       data: [f0], // the frame
 | ||||
|  |  | |||
|  | @ -162,6 +162,8 @@ export function applyFieldOverrides(options: ApplyFieldOverrideOptions): DataFra | |||
|       const { range, newGlobalRange } = calculateRange(config, field, globalRange, options.data!); | ||||
|       globalRange = newGlobalRange; | ||||
| 
 | ||||
|       // Clear any cached displayName as it can change during field overrides process
 | ||||
|       field.state!.displayName = null; | ||||
|       field.state!.seriesIndex = seriesIndex; | ||||
|       field.state!.range = range; | ||||
|       field.type = type; | ||||
|  |  | |||
|  | @ -199,7 +199,6 @@ export interface FeatureToggles { | |||
|   alertingApiServer?: boolean; | ||||
|   dashboardRestoreUI?: boolean; | ||||
|   cloudWatchRoundUpEndTime?: boolean; | ||||
|   bodyScrolling?: boolean; | ||||
|   cloudwatchMetricInsightsCrossAccount?: boolean; | ||||
|   prometheusAzureOverrideAudience?: boolean; | ||||
|   alertingFilterV2?: boolean; | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ | |||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@rollup/plugin-node-resolve": "15.2.4", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/node": "20.16.6", | ||||
|     "esbuild": "0.24.0", | ||||
|     "rimraf": "6.0.1", | ||||
|     "rollup": "2.79.1", | ||||
|  |  | |||
|  | @ -67,8 +67,8 @@ | |||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/d3": "^7", | ||||
|     "@types/jest": "^29.5.4", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-virtualized-auto-sizer": "1.0.4", | ||||
|     "@types/tinycolor2": "1.4.6", | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ | |||
|     "@svgr/plugin-prettier": "^8.1.0", | ||||
|     "@svgr/plugin-svgo": "^8.1.0", | ||||
|     "@types/babel__core": "^7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "esbuild": "0.24.0", | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "^29.5.4", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/systemjs": "6.15.1", | ||||
|     "@types/testing-library__jest-dom": "5.14.9", | ||||
|  |  | |||
|  | @ -20,5 +20,5 @@ | |||
|     "typescript": "5.5.4", | ||||
|     "webpack": "5.94.0" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ | |||
|   }, | ||||
|   "dependencies": { | ||||
|     "@emotion/css": "11.11.2", | ||||
|     "@floating-ui/react": "0.26.23", | ||||
|     "@floating-ui/react": "0.26.24", | ||||
|     "@grafana/data": "11.3.0-pre", | ||||
|     "@grafana/experimental": "1.8.0", | ||||
|     "@grafana/faro-web-sdk": "1.10.0", | ||||
|  | @ -91,8 +91,8 @@ | |||
|     "@types/eslint": "8.56.10", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/jquery": "3.5.30", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/pluralize": "^0.0.33", | ||||
|     "@types/prismjs": "1.26.4", | ||||
|     "@types/react": "18.3.3", | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ | |||
|     "@types/angular": "1.8.9", | ||||
|     "@types/history": "4.7.11", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "@types/systemjs": "6.15.1", | ||||
|  |  | |||
|  | @ -41,8 +41,8 @@ | |||
|     "@testing-library/react-hooks": "^8.0.1", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "^29.5.4", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "@types/react-virtualized-auto-sizer": "1.0.4", | ||||
|  |  | |||
|  | @ -49,7 +49,7 @@ | |||
|   "dependencies": { | ||||
|     "@emotion/css": "11.11.2", | ||||
|     "@emotion/react": "11.11.4", | ||||
|     "@floating-ui/react": "0.26.23", | ||||
|     "@floating-ui/react": "0.26.24", | ||||
|     "@grafana/data": "11.3.0-pre", | ||||
|     "@grafana/e2e-selectors": "11.3.0-pre", | ||||
|     "@grafana/faro-web-sdk": "^1.3.6", | ||||
|  | @ -64,7 +64,7 @@ | |||
|     "@react-aria/utils": "3.25.2", | ||||
|     "@tanstack/react-virtual": "^3.5.1", | ||||
|     "@types/jquery": "3.5.30", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/react-table": "7.7.20", | ||||
|     "ansicolor": "1.1.100", | ||||
|     "calculate-size": "1.1.1", | ||||
|  | @ -145,7 +145,7 @@ | |||
|     "@types/is-hotkey": "0.1.10", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/mock-raf": "1.0.6", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/prismjs": "1.26.4", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-color": "3.0.12", | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ export interface WithContextMenuProps { | |||
| export const WithContextMenu = ({ children, renderMenuItems, focusOnOpen = true }: WithContextMenuProps) => { | ||||
|   const [isMenuOpen, setIsMenuOpen] = useState(false); | ||||
|   const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 }); | ||||
|   const isBodyScrolling = window.grafanaBootData?.settings.featureToggles.bodyScrolling; | ||||
|   return ( | ||||
|     <> | ||||
|       {children({ | ||||
|  | @ -23,7 +22,7 @@ export const WithContextMenu = ({ children, renderMenuItems, focusOnOpen = true | |||
|           setIsMenuOpen(true); | ||||
|           setMenuPosition({ | ||||
|             x: e.pageX, | ||||
|             y: isBodyScrolling ? e.pageY - window.scrollY : e.pageY, | ||||
|             y: e.pageY - window.scrollY, | ||||
|           }); | ||||
|         }, | ||||
|       })} | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ import { GrafanaTheme2, dateTimeParse, DateTime, TimeZone } from '@grafana/data' | |||
| import { useStyles2 } from '../../../themes'; | ||||
| import { t } from '../../../utils/i18n'; | ||||
| import { Icon } from '../../Icon/Icon'; | ||||
| import { WeekStart } from '../WeekStartPicker'; | ||||
| import { getWeekStart, WeekStart } from '../WeekStartPicker'; | ||||
| import { adjustDateForReactCalendar } from '../utils/adjustDateForReactCalendar'; | ||||
| 
 | ||||
| import { TimePickerCalendarProps } from './TimePickerCalendar'; | ||||
|  | @ -19,10 +19,11 @@ const weekStartMap: Record<WeekStart, CalendarType> = { | |||
|   monday: 'iso8601', | ||||
| }; | ||||
| 
 | ||||
| export function Body({ onChange, from, to, timeZone, weekStart = 'monday' }: TimePickerCalendarProps) { | ||||
| export function Body({ onChange, from, to, timeZone, weekStart }: TimePickerCalendarProps) { | ||||
|   const value = inputToValue(from, to, new Date(), timeZone); | ||||
|   const onCalendarChange = useOnCalendarChange(onChange, timeZone); | ||||
|   const styles = useStyles2(getBodyStyles); | ||||
|   const weekStartValue = getWeekStart(weekStart); | ||||
| 
 | ||||
|   return ( | ||||
|     <Calendar | ||||
|  | @ -38,7 +39,7 @@ export function Body({ onChange, from, to, timeZone, weekStart = 'monday' }: Tim | |||
|       prevAriaLabel={t('time-picker.calendar.previous-month', 'Previous month')} | ||||
|       onChange={onCalendarChange} | ||||
|       locale="en" | ||||
|       calendarType={weekStartMap[weekStart]} | ||||
|       calendarType={weekStartMap[weekStartValue]} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import { useCallback, useMemo } from 'react'; | ||||
| 
 | ||||
| import { BootData } from '@grafana/data'; | ||||
| import { selectors } from '@grafana/e2e-selectors'; | ||||
| 
 | ||||
| import { Combobox, ComboboxOption } from '../Combobox/Combobox'; | ||||
|  | @ -26,13 +27,28 @@ const isWeekStart = (value: string): value is WeekStart => { | |||
|   return ['saturday', 'sunday', 'monday'].includes(value); | ||||
| }; | ||||
| 
 | ||||
| export const getWeekStart = (value: string): WeekStart => { | ||||
|   if (isWeekStart(value)) { | ||||
|     return value; | ||||
| declare global { | ||||
|   interface Window { | ||||
|     grafanaBootData?: BootData; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Returns the system or user defined week start (as defined in bootData) | ||||
|  * Or you can pass in an override weekStart string and have it be validated and returned as WeekStart type if valid | ||||
|  */ | ||||
| export function getWeekStart(override?: string): WeekStart { | ||||
|   if (override && isWeekStart(override)) { | ||||
|     return override; | ||||
|   } | ||||
| 
 | ||||
|   const preference = window?.grafanaBootData?.user?.weekStart; | ||||
|   if (preference && isWeekStart(preference)) { | ||||
|     return preference; | ||||
|   } | ||||
| 
 | ||||
|   return 'monday'; | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| export const WeekStartPicker = (props: Props) => { | ||||
|   const { onChange, width, autoFocus = false, onBlur, value, disabled = false, inputId } = props; | ||||
|  |  | |||
|  | @ -55,21 +55,13 @@ export function PortalContainer() { | |||
| } | ||||
| 
 | ||||
| const getStyles = (theme: GrafanaTheme2) => { | ||||
|   const isBodyScrolling = window.grafanaBootData?.settings.featureToggles.bodyScrolling; | ||||
|   return { | ||||
|     grafanaPortalContainer: css( | ||||
|       isBodyScrolling | ||||
|         ? { | ||||
|             position: 'fixed', | ||||
|             top: 0, | ||||
|             width: '100%', | ||||
|             zIndex: theme.zIndex.portal, | ||||
|           } | ||||
|         : { | ||||
|             position: 'absolute', | ||||
|             width: '100%', | ||||
|           } | ||||
|     ), | ||||
|     grafanaPortalContainer: css({ | ||||
|       position: 'fixed', | ||||
|       top: 0, | ||||
|       width: '100%', | ||||
|       zIndex: theme.zIndex.portal, | ||||
|     }), | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,9 +5,6 @@ import { GrafanaTheme2, ThemeTypographyVariant } from '@grafana/data'; | |||
| import { getFocusStyles } from '../mixins'; | ||||
| 
 | ||||
| export function getElementStyles(theme: GrafanaTheme2) { | ||||
|   // TODO can we get the feature toggle in a better way?
 | ||||
|   const isBodyScrolling = window.grafanaBootData?.settings.featureToggles.bodyScrolling; | ||||
| 
 | ||||
|   return css({ | ||||
|     '*, *::before, *::after': { | ||||
|       boxSizing: 'inherit', | ||||
|  | @ -40,26 +37,24 @@ export function getElementStyles(theme: GrafanaTheme2) { | |||
|     body: { | ||||
|       height: '100%', | ||||
|       width: '100%', | ||||
|       position: isBodyScrolling ? 'unset' : 'absolute', | ||||
|       position: 'unset', | ||||
|       color: theme.colors.text.primary, | ||||
|       backgroundColor: theme.colors.background.canvas, | ||||
|       // react select tries prevent scrolling by setting overflow/padding-right on the body
 | ||||
|       // Need type assertion here due to the use of !important
 | ||||
|       // see https://github.com/frenic/csstype/issues/114#issuecomment-697201978
 | ||||
|       // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
 | ||||
|       overflowY: 'auto !important' as 'auto', | ||||
|       paddingRight: '0 !important', | ||||
|       '@media print': { | ||||
|         overflow: 'visible', | ||||
|       }, | ||||
|       '@page': { | ||||
|         margin: 0, | ||||
|         size: 'auto', | ||||
|         padding: 0, | ||||
|       }, | ||||
|       ...theme.typography.body, | ||||
|       ...(isBodyScrolling && { | ||||
|         // react select tries prevent scrolling by setting overflow/padding-right on the body
 | ||||
|         // Need type assertion here due to the use of !important
 | ||||
|         // see https://github.com/frenic/csstype/issues/114#issuecomment-697201978
 | ||||
|         // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
 | ||||
|         overflowY: 'auto !important' as 'auto', | ||||
|         paddingRight: '0 !important', | ||||
|         '@media print': { | ||||
|           overflow: 'visible', | ||||
|         }, | ||||
|         '@page': { | ||||
|           margin: 0, | ||||
|           size: 'auto', | ||||
|           padding: 0, | ||||
|         }, | ||||
|       }), | ||||
|     }, | ||||
| 
 | ||||
|     'h1, .h1': getVariantStyles(theme.typography.h1), | ||||
|  |  | |||
|  | @ -5,42 +5,21 @@ import { GrafanaTheme2 } from '@grafana/data'; | |||
| export function getPageStyles(theme: GrafanaTheme2) { | ||||
|   const maxWidthBreakpoint = | ||||
|     theme.breakpoints.values.xxl + theme.spacing.gridSize * 2 + theme.components.sidemenu.width; | ||||
|   const isBodyScrolling = window.grafanaBootData?.settings.featureToggles.bodyScrolling; | ||||
| 
 | ||||
|   return css({ | ||||
|     '.grafana-app': isBodyScrolling | ||||
|       ? { | ||||
|           display: 'flex', | ||||
|           flexDirection: 'column', | ||||
|           height: '100vh', | ||||
|         } | ||||
|       : { | ||||
|           display: 'flex', | ||||
|           alignItems: 'stretch', | ||||
|           position: 'absolute', | ||||
|           width: '100%', | ||||
|           height: '100%', | ||||
|           top: 0, | ||||
|           left: 0, | ||||
|         }, | ||||
|     '.grafana-app': { | ||||
|       display: 'flex', | ||||
|       flexDirection: 'column', | ||||
|       height: '100vh', | ||||
|     }, | ||||
| 
 | ||||
|     '.main-view': isBodyScrolling | ||||
|       ? { | ||||
|           display: 'flex', | ||||
|           flexDirection: 'column', | ||||
|           flexGrow: 1, | ||||
|           position: 'relative', | ||||
|           minWidth: 0, | ||||
|         } | ||||
|       : { | ||||
|           position: 'relative', | ||||
|           display: 'flex', | ||||
|           flexDirection: 'column', | ||||
|           flexGrow: 1, | ||||
|           height: '100%', | ||||
|           flex: '1 1 0', | ||||
|           minWidth: 0, | ||||
|         }, | ||||
|     '.main-view': { | ||||
|       display: 'flex', | ||||
|       flexDirection: 'column', | ||||
|       flexGrow: 1, | ||||
|       position: 'relative', | ||||
|       minWidth: 0, | ||||
|     }, | ||||
| 
 | ||||
|     '.page-scrollbar-content': { | ||||
|       display: 'flex', | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ module github.com/grafana/grafana/pkg/apimachinery | |||
| go 1.23.1 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/grafana/authlib v0.0.0-20240906122029-0100695765b9 // @grafana/identity-access-team | ||||
| 	github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 // @grafana/identity-access-team | ||||
| 	github.com/grafana/authlib/claims v0.0.0-20240903121118-16441568af1e // @grafana/identity-access-team | ||||
| 	github.com/stretchr/testify v1.9.0 | ||||
| 	k8s.io/apimachinery v0.31.0 | ||||
|  |  | |||
|  | @ -28,8 +28,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN | |||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= | ||||
| github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| github.com/grafana/authlib v0.0.0-20240906122029-0100695765b9 h1:e+kFqd2sECBhbxOV1NoVxsudLygNQuu9bO+7FjNTkXo= | ||||
| github.com/grafana/authlib v0.0.0-20240906122029-0100695765b9/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY= | ||||
| github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 h1:zYF/RBulpvMqPYR3gbzJZ8t/j/Eymn5FNidSYkueNCA= | ||||
| github.com/grafana/authlib v0.0.0-20240919120951-58259833c564/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY= | ||||
| github.com/grafana/authlib/claims v0.0.0-20240903121118-16441568af1e h1:ng5SopWamGS0MHaCj2e5huWYxAfMeCrj1l/dbJnfiow= | ||||
| github.com/grafana/authlib/claims v0.0.0-20240903121118-16441568af1e/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A= | ||||
| github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= | ||||
|  |  | |||
|  | @ -166,7 +166,7 @@ func AddKnownTypes(scheme *runtime.Scheme, version string) { | |||
| 		&ServiceAccountTokenList{}, | ||||
| 		&Team{}, | ||||
| 		&TeamList{}, | ||||
| 		&IdentityDisplayResults{}, | ||||
| 		&DisplayList{}, | ||||
| 		&SSOSetting{}, | ||||
| 		&SSOSettingList{}, | ||||
| 		&TeamBinding{}, | ||||
|  |  | |||
|  | @ -7,23 +7,24 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | ||||
| type IdentityDisplayResults struct { | ||||
| type DisplayList struct { | ||||
| 	metav1.TypeMeta `json:",inline"` | ||||
| 	metav1.ListMeta `json:"metadata,omitempty"` | ||||
| 
 | ||||
| 	// Request keys used to lookup the display value
 | ||||
| 	// +listType=set
 | ||||
| 	Keys []string `json:"keys"` | ||||
| 
 | ||||
| 	// Matching items (the caller may need to remap from keys to results)
 | ||||
| 	// +listType=atomic
 | ||||
| 	Display []IdentityDisplay `json:"display"` | ||||
| 
 | ||||
| 	// Input keys that were not useable
 | ||||
| 	// +listType=set
 | ||||
| 	InvalidKeys []string `json:"invalidKeys,omitempty"` | ||||
| 
 | ||||
| 	// Matching items (the caller may need to remap from keys to results)
 | ||||
| 	// +listType=atomic
 | ||||
| 	Items []Display `json:"display"` | ||||
| } | ||||
| 
 | ||||
| type IdentityDisplay struct { | ||||
| type Display struct { | ||||
| 	Identity IdentityRef `json:"identity"` | ||||
| 
 | ||||
| 	// Display name for identity.
 | ||||
|  | @ -68,7 +68,7 @@ type TeamMemberList struct { | |||
| } | ||||
| 
 | ||||
| type TeamMember struct { | ||||
| 	IdentityDisplay `json:",inline"` | ||||
| 	Display `json:",inline"` | ||||
| 
 | ||||
| 	// External is set if member ship was synced from external IDP.
 | ||||
| 	External bool `json:"external,omitempty"` | ||||
|  |  | |||
|  | @ -12,56 +12,57 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *IdentityDisplay) DeepCopyInto(out *IdentityDisplay) { | ||||
| func (in *Display) DeepCopyInto(out *Display) { | ||||
| 	*out = *in | ||||
| 	out.Identity = in.Identity | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IdentityDisplay.
 | ||||
| func (in *IdentityDisplay) DeepCopy() *IdentityDisplay { | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Display.
 | ||||
| func (in *Display) DeepCopy() *Display { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(IdentityDisplay) | ||||
| 	out := new(Display) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *IdentityDisplayResults) DeepCopyInto(out *IdentityDisplayResults) { | ||||
| func (in *DisplayList) DeepCopyInto(out *DisplayList) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ListMeta.DeepCopyInto(&out.ListMeta) | ||||
| 	if in.Keys != nil { | ||||
| 		in, out := &in.Keys, &out.Keys | ||||
| 		*out = make([]string, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	if in.Display != nil { | ||||
| 		in, out := &in.Display, &out.Display | ||||
| 		*out = make([]IdentityDisplay, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	if in.InvalidKeys != nil { | ||||
| 		in, out := &in.InvalidKeys, &out.InvalidKeys | ||||
| 		*out = make([]string, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	if in.Items != nil { | ||||
| 		in, out := &in.Items, &out.Items | ||||
| 		*out = make([]Display, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IdentityDisplayResults.
 | ||||
| func (in *IdentityDisplayResults) DeepCopy() *IdentityDisplayResults { | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DisplayList.
 | ||||
| func (in *DisplayList) DeepCopy() *DisplayList { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(IdentityDisplayResults) | ||||
| 	out := new(DisplayList) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *IdentityDisplayResults) DeepCopyObject() runtime.Object { | ||||
| func (in *DisplayList) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
|  | @ -440,7 +441,7 @@ func (in *TeamList) DeepCopyObject() runtime.Object { | |||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *TeamMember) DeepCopyInto(out *TeamMember) { | ||||
| 	*out = *in | ||||
| 	out.IdentityDisplay = in.IdentityDisplay | ||||
| 	out.Display = in.Display | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,8 +14,8 @@ import ( | |||
| 
 | ||||
| func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { | ||||
| 	return map[string]common.OpenAPIDefinition{ | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplay":         schema_pkg_apis_iam_v0alpha1_IdentityDisplay(ref), | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplayResults":  schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref), | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.Display":                 schema_pkg_apis_iam_v0alpha1_Display(ref), | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.DisplayList":             schema_pkg_apis_iam_v0alpha1_DisplayList(ref), | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityRef":             schema_pkg_apis_iam_v0alpha1_IdentityRef(ref), | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSetting":              schema_pkg_apis_iam_v0alpha1_SSOSetting(ref), | ||||
| 		"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.SSOSettingList":          schema_pkg_apis_iam_v0alpha1_SSOSettingList(ref), | ||||
|  | @ -43,7 +43,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func schema_pkg_apis_iam_v0alpha1_IdentityDisplay(ref common.ReferenceCallback) common.OpenAPIDefinition { | ||||
| func schema_pkg_apis_iam_v0alpha1_Display(ref common.ReferenceCallback) common.OpenAPIDefinition { | ||||
| 	return common.OpenAPIDefinition{ | ||||
| 		Schema: spec.Schema{ | ||||
| 			SchemaProps: spec.SchemaProps{ | ||||
|  | @ -86,7 +86,7 @@ func schema_pkg_apis_iam_v0alpha1_IdentityDisplay(ref common.ReferenceCallback) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref common.ReferenceCallback) common.OpenAPIDefinition { | ||||
| func schema_pkg_apis_iam_v0alpha1_DisplayList(ref common.ReferenceCallback) common.OpenAPIDefinition { | ||||
| 	return common.OpenAPIDefinition{ | ||||
| 		Schema: spec.Schema{ | ||||
| 			SchemaProps: spec.SchemaProps{ | ||||
|  | @ -106,6 +106,12 @@ func schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref common.ReferenceCal | |||
| 							Format:      "", | ||||
| 						}, | ||||
| 					}, | ||||
| 					"metadata": { | ||||
| 						SchemaProps: spec.SchemaProps{ | ||||
| 							Default: map[string]interface{}{}, | ||||
| 							Ref:     ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), | ||||
| 						}, | ||||
| 					}, | ||||
| 					"keys": { | ||||
| 						VendorExtensible: spec.VendorExtensible{ | ||||
| 							Extensions: spec.Extensions{ | ||||
|  | @ -126,25 +132,6 @@ func schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref common.ReferenceCal | |||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					"display": { | ||||
| 						VendorExtensible: spec.VendorExtensible{ | ||||
| 							Extensions: spec.Extensions{ | ||||
| 								"x-kubernetes-list-type": "atomic", | ||||
| 							}, | ||||
| 						}, | ||||
| 						SchemaProps: spec.SchemaProps{ | ||||
| 							Description: "Matching items (the caller may need to remap from keys to results)", | ||||
| 							Type:        []string{"array"}, | ||||
| 							Items: &spec.SchemaOrArray{ | ||||
| 								Schema: &spec.Schema{ | ||||
| 									SchemaProps: spec.SchemaProps{ | ||||
| 										Default: map[string]interface{}{}, | ||||
| 										Ref:     ref("github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplay"), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					"invalidKeys": { | ||||
| 						VendorExtensible: spec.VendorExtensible{ | ||||
| 							Extensions: spec.Extensions{ | ||||
|  | @ -165,12 +152,31 @@ func schema_pkg_apis_iam_v0alpha1_IdentityDisplayResults(ref common.ReferenceCal | |||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					"display": { | ||||
| 						VendorExtensible: spec.VendorExtensible{ | ||||
| 							Extensions: spec.Extensions{ | ||||
| 								"x-kubernetes-list-type": "atomic", | ||||
| 							}, | ||||
| 						}, | ||||
| 						SchemaProps: spec.SchemaProps{ | ||||
| 							Description: "Matching items (the caller may need to remap from keys to results)", | ||||
| 							Type:        []string{"array"}, | ||||
| 							Items: &spec.SchemaOrArray{ | ||||
| 								Schema: &spec.Schema{ | ||||
| 									SchemaProps: spec.SchemaProps{ | ||||
| 										Default: map[string]interface{}{}, | ||||
| 										Ref:     ref("github.com/grafana/grafana/pkg/apis/iam/v0alpha1.Display"), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				Required: []string{"keys", "display"}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Dependencies: []string{ | ||||
| 			"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.IdentityDisplay"}, | ||||
| 			"github.com/grafana/grafana/pkg/apis/iam/v0alpha1.Display", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,2 +1,4 @@ | |||
| API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/iam/v0alpha1,DisplayList,Items | ||||
| API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/iam/v0alpha1,TeamBindingSpec,Subjects | ||||
| API rule violation: names_match,github.com/grafana/grafana/pkg/apis/iam/v0alpha1,IdentityDisplay,InternalID | ||||
| API rule violation: names_match,github.com/grafana/grafana/pkg/apis/iam/v0alpha1,Display,InternalID | ||||
| API rule violation: names_match,github.com/grafana/grafana/pkg/apis/iam/v0alpha1,DisplayList,Items | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ package grpcplugin | |||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"google.golang.org/grpc" | ||||
| 
 | ||||
|  | @ -15,7 +14,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	errClientNotStarted = errors.New("plugin client has not been started") | ||||
| 	errClientNotAvailable = errors.New("plugin client not available") | ||||
| ) | ||||
| 
 | ||||
| var _ ProtoClient = (*protoClient)(nil) | ||||
|  | @ -31,20 +30,12 @@ type ProtoClient interface { | |||
| 	PID(context.Context) (string, error) | ||||
| 	PluginID() string | ||||
| 	PluginVersion() string | ||||
| 	PluginJSON() plugins.JSONData | ||||
| 	Backend() backendplugin.Plugin | ||||
| 	Logger() log.Logger | ||||
| 	Start(context.Context) error | ||||
| 	Stop(context.Context) error | ||||
| 	Running(context.Context) bool | ||||
| } | ||||
| 
 | ||||
| type protoClient struct { | ||||
| 	plugin        *grpcPlugin | ||||
| 	pluginVersion string | ||||
| 	pluginJSON    plugins.JSONData | ||||
| 
 | ||||
| 	mu sync.RWMutex | ||||
| 	plugin     *grpcPlugin | ||||
| 	pluginJSON plugins.JSONData | ||||
| } | ||||
| 
 | ||||
| type ProtoClientOpts struct { | ||||
|  | @ -68,12 +59,12 @@ func NewProtoClient(opts ProtoClientOpts) (ProtoClient, error) { | |||
| 		func() []string { return opts.Env }, | ||||
| 	) | ||||
| 
 | ||||
| 	return &protoClient{plugin: p, pluginVersion: opts.PluginJSON.Info.Version, pluginJSON: opts.PluginJSON}, nil | ||||
| 	return &protoClient{plugin: p, pluginJSON: opts.PluginJSON}, nil | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) PID(ctx context.Context) (string, error) { | ||||
| 	if _, exists := r.client(ctx); !exists { | ||||
| 		return "", errClientNotStarted | ||||
| 		return "", errClientNotAvailable | ||||
| 	} | ||||
| 	return r.plugin.client.ID(), nil | ||||
| } | ||||
|  | @ -83,11 +74,7 @@ func (r *protoClient) PluginID() string { | |||
| } | ||||
| 
 | ||||
| func (r *protoClient) PluginVersion() string { | ||||
| 	return r.pluginVersion | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) PluginJSON() plugins.JSONData { | ||||
| 	return r.pluginJSON | ||||
| 	return r.pluginJSON.Info.Version | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) Backend() backendplugin.Plugin { | ||||
|  | @ -98,43 +85,14 @@ func (r *protoClient) Logger() log.Logger { | |||
| 	return r.plugin.logger | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) Start(ctx context.Context) error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	return r.plugin.Start(ctx) | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) Stop(ctx context.Context) error { | ||||
| 	r.mu.Lock() | ||||
| 	defer r.mu.Unlock() | ||||
| 	return r.plugin.Stop(ctx) | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) Running(_ context.Context) bool { | ||||
| 	r.mu.RLock() | ||||
| 	defer r.mu.RUnlock() | ||||
| 	return !r.plugin.Exited() | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) client(ctx context.Context) (*ClientV2, bool) { | ||||
| 	if !r.Running(ctx) { | ||||
| 		return nil, false | ||||
| 	} | ||||
| 
 | ||||
| 	r.mu.RLock() | ||||
| 	if r.plugin.pluginClient == nil { | ||||
| 		r.mu.RUnlock() | ||||
| 		return nil, false | ||||
| 	} | ||||
| 	pc := r.plugin.pluginClient | ||||
| 	r.mu.RUnlock() | ||||
| 	return pc, true | ||||
| 	return r.plugin.getPluginClient(ctx) | ||||
| } | ||||
| 
 | ||||
| func (r *protoClient) QueryData(ctx context.Context, in *pluginv2.QueryDataRequest, opts ...grpc.CallOption) (*pluginv2.QueryDataResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.DataClient.QueryData(ctx, in, opts...) | ||||
| } | ||||
|  | @ -142,7 +100,7 @@ func (r *protoClient) QueryData(ctx context.Context, in *pluginv2.QueryDataReque | |||
| func (r *protoClient) CallResource(ctx context.Context, in *pluginv2.CallResourceRequest, opts ...grpc.CallOption) (pluginv2.Resource_CallResourceClient, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.ResourceClient.CallResource(ctx, in, opts...) | ||||
| } | ||||
|  | @ -150,7 +108,7 @@ func (r *protoClient) CallResource(ctx context.Context, in *pluginv2.CallResourc | |||
| func (r *protoClient) CheckHealth(ctx context.Context, in *pluginv2.CheckHealthRequest, opts ...grpc.CallOption) (*pluginv2.CheckHealthResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.DiagnosticsClient.CheckHealth(ctx, in, opts...) | ||||
| } | ||||
|  | @ -158,7 +116,7 @@ func (r *protoClient) CheckHealth(ctx context.Context, in *pluginv2.CheckHealthR | |||
| func (r *protoClient) CollectMetrics(ctx context.Context, in *pluginv2.CollectMetricsRequest, opts ...grpc.CallOption) (*pluginv2.CollectMetricsResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.DiagnosticsClient.CollectMetrics(ctx, in, opts...) | ||||
| } | ||||
|  | @ -166,7 +124,7 @@ func (r *protoClient) CollectMetrics(ctx context.Context, in *pluginv2.CollectMe | |||
| func (r *protoClient) SubscribeStream(ctx context.Context, in *pluginv2.SubscribeStreamRequest, opts ...grpc.CallOption) (*pluginv2.SubscribeStreamResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.StreamClient.SubscribeStream(ctx, in, opts...) | ||||
| } | ||||
|  | @ -174,7 +132,7 @@ func (r *protoClient) SubscribeStream(ctx context.Context, in *pluginv2.Subscrib | |||
| func (r *protoClient) RunStream(ctx context.Context, in *pluginv2.RunStreamRequest, opts ...grpc.CallOption) (pluginv2.Stream_RunStreamClient, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.StreamClient.RunStream(ctx, in, opts...) | ||||
| } | ||||
|  | @ -182,7 +140,7 @@ func (r *protoClient) RunStream(ctx context.Context, in *pluginv2.RunStreamReque | |||
| func (r *protoClient) PublishStream(ctx context.Context, in *pluginv2.PublishStreamRequest, opts ...grpc.CallOption) (*pluginv2.PublishStreamResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.StreamClient.PublishStream(ctx, in, opts...) | ||||
| } | ||||
|  | @ -190,7 +148,7 @@ func (r *protoClient) PublishStream(ctx context.Context, in *pluginv2.PublishStr | |||
| func (r *protoClient) ValidateAdmission(ctx context.Context, in *pluginv2.AdmissionRequest, opts ...grpc.CallOption) (*pluginv2.ValidationResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.AdmissionClient.ValidateAdmission(ctx, in, opts...) | ||||
| } | ||||
|  | @ -198,7 +156,7 @@ func (r *protoClient) ValidateAdmission(ctx context.Context, in *pluginv2.Admiss | |||
| func (r *protoClient) MutateAdmission(ctx context.Context, in *pluginv2.AdmissionRequest, opts ...grpc.CallOption) (*pluginv2.MutationResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.AdmissionClient.MutateAdmission(ctx, in, opts...) | ||||
| } | ||||
|  | @ -206,7 +164,7 @@ func (r *protoClient) MutateAdmission(ctx context.Context, in *pluginv2.Admissio | |||
| func (r *protoClient) ConvertObjects(ctx context.Context, in *pluginv2.ConversionRequest, opts ...grpc.CallOption) (*pluginv2.ConversionResponse, error) { | ||||
| 	c, exists := r.client(ctx) | ||||
| 	if !exists { | ||||
| 		return nil, errClientNotStarted | ||||
| 		return nil, errClientNotAvailable | ||||
| 	} | ||||
| 	return c.ConversionClient.ConvertObjects(ctx, in, opts...) | ||||
| } | ||||
|  |  | |||
|  | @ -14,16 +14,6 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/plugins/log" | ||||
| ) | ||||
| 
 | ||||
| type pluginClient interface { | ||||
| 	backend.CollectMetricsHandler | ||||
| 	backend.CheckHealthHandler | ||||
| 	backend.QueryDataHandler | ||||
| 	backend.CallResourceHandler | ||||
| 	backend.AdmissionHandler | ||||
| 	backend.ConversionHandler | ||||
| 	backend.StreamHandler | ||||
| } | ||||
| 
 | ||||
| type grpcPlugin struct { | ||||
| 	descriptor     PluginDescriptor | ||||
| 	clientFactory  func() *plugin.Client | ||||
|  | @ -32,8 +22,19 @@ type grpcPlugin struct { | |||
| 	logger         log.Logger | ||||
| 	mutex          sync.RWMutex | ||||
| 	decommissioned bool | ||||
| 	state          pluginState | ||||
| } | ||||
| 
 | ||||
| type pluginState int | ||||
| 
 | ||||
| const ( | ||||
| 	pluginStateNotStarted pluginState = iota | ||||
| 	pluginStateStartInit | ||||
| 	pluginStateStartSuccess | ||||
| 	pluginStateStartFail | ||||
| 	pluginStateStopped | ||||
| ) | ||||
| 
 | ||||
| // newPlugin allocates and returns a new gRPC (external) backendplugin.Plugin.
 | ||||
| func newPlugin(descriptor PluginDescriptor) backendplugin.PluginFactoryFunc { | ||||
| 	return func(pluginID string, logger log.Logger, env func() []string) (backendplugin.Plugin, error) { | ||||
|  | @ -48,6 +49,7 @@ func newGrpcPlugin(descriptor PluginDescriptor, logger log.Logger, env func() [] | |||
| 		clientFactory: func() *plugin.Client { | ||||
| 			return plugin.NewClient(newClientConfig(descriptor.executablePath, descriptor.executableArgs, env(), descriptor.skipHostEnvVars, logger, descriptor.versionedPlugins)) | ||||
| 		}, | ||||
| 		state: pluginStateNotStarted, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -63,21 +65,27 @@ func (p *grpcPlugin) Start(_ context.Context) error { | |||
| 	p.mutex.Lock() | ||||
| 	defer p.mutex.Unlock() | ||||
| 
 | ||||
| 	p.state = pluginStateStartInit | ||||
| 
 | ||||
| 	p.client = p.clientFactory() | ||||
| 	rpcClient, err := p.client.Client() | ||||
| 	if err != nil { | ||||
| 		p.state = pluginStateStartFail | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if p.client.NegotiatedVersion() < 2 { | ||||
| 		p.state = pluginStateStartFail | ||||
| 		return errors.New("plugin protocol version not supported") | ||||
| 	} | ||||
| 	p.pluginClient, err = newClientV2(p.descriptor, p.logger, rpcClient) | ||||
| 	if err != nil { | ||||
| 		p.state = pluginStateStartFail | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if p.pluginClient == nil { | ||||
| 		p.state = pluginStateStartFail | ||||
| 		return errors.New("no compatible plugin implementation found") | ||||
| 	} | ||||
| 
 | ||||
|  | @ -89,6 +97,7 @@ func (p *grpcPlugin) Start(_ context.Context) error { | |||
| 		p.logger.Warn("Plugin process is running with elevated privileges. This is not recommended") | ||||
| 	} | ||||
| 
 | ||||
| 	p.state = pluginStateStartSuccess | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  | @ -99,6 +108,7 @@ func (p *grpcPlugin) Stop(_ context.Context) error { | |||
| 	if p.client != nil { | ||||
| 		p.client.Kill() | ||||
| 	} | ||||
| 	p.state = pluginStateStopped | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  | @ -134,94 +144,110 @@ func (p *grpcPlugin) Target() backendplugin.Target { | |||
| 	return backendplugin.TargetLocal | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) getPluginClient() (pluginClient, bool) { | ||||
| func (p *grpcPlugin) getPluginClient(ctx context.Context) (*ClientV2, bool) { | ||||
| 	p.mutex.RLock() | ||||
| 	if p.client == nil || p.client.Exited() || p.pluginClient == nil { | ||||
| 		p.mutex.RUnlock() | ||||
| 		return nil, false | ||||
| 	defer p.mutex.RUnlock() | ||||
| 	if p.client != nil && !p.client.Exited() && p.pluginClient != nil { | ||||
| 		return p.pluginClient, true | ||||
| 	} | ||||
| 	pluginClient := p.pluginClient | ||||
| 	p.mutex.RUnlock() | ||||
| 	return pluginClient, true | ||||
| 
 | ||||
| 	logger := p.Logger().FromContext(ctx) | ||||
| 	if p.state == pluginStateNotStarted { | ||||
| 		logger.Debug("Plugin client has not been started yet") | ||||
| 	} | ||||
| 
 | ||||
| 	if p.state == pluginStateStartInit { | ||||
| 		logger.Debug("Plugin client is starting") | ||||
| 	} | ||||
| 
 | ||||
| 	if p.state == pluginStateStartFail { | ||||
| 		logger.Debug("Plugin client failed to start") | ||||
| 	} | ||||
| 
 | ||||
| 	if p.state == pluginStateStopped { | ||||
| 		logger.Debug("Plugin client has stopped") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, false | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.CollectMetrics(ctx, req) | ||||
| 	return pc.CollectMetrics(ctx, req) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.CheckHealth(ctx, req) | ||||
| 	return pc.CheckHealth(ctx, req) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 
 | ||||
| 	return pluginClient.QueryData(ctx, req) | ||||
| 	return pc.QueryData(ctx, req) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.CallResource(ctx, req, sender) | ||||
| 	return pc.CallResource(ctx, req, sender) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) SubscribeStream(ctx context.Context, request *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.SubscribeStream(ctx, request) | ||||
| 	return pc.SubscribeStream(ctx, request) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) PublishStream(ctx context.Context, request *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.PublishStream(ctx, request) | ||||
| 	return pc.PublishStream(ctx, request) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.RunStream(ctx, req, sender) | ||||
| 	return pc.RunStream(ctx, req, sender) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) ValidateAdmission(ctx context.Context, request *backend.AdmissionRequest) (*backend.ValidationResponse, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.ValidateAdmission(ctx, request) | ||||
| 	return pc.ValidateAdmission(ctx, request) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) MutateAdmission(ctx context.Context, request *backend.AdmissionRequest) (*backend.MutationResponse, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.MutateAdmission(ctx, request) | ||||
| 	return pc.MutateAdmission(ctx, request) | ||||
| } | ||||
| 
 | ||||
| func (p *grpcPlugin) ConvertObjects(ctx context.Context, request *backend.ConversionRequest) (*backend.ConversionResponse, error) { | ||||
| 	pluginClient, ok := p.getPluginClient() | ||||
| 	pc, ok := p.getPluginClient(ctx) | ||||
| 	if !ok { | ||||
| 		return nil, plugins.ErrPluginUnavailable | ||||
| 	} | ||||
| 	return pluginClient.ConvertObjects(ctx, request) | ||||
| 	return pc.ConvertObjects(ctx, request) | ||||
| } | ||||
|  |  | |||
|  | @ -79,6 +79,10 @@ func RegisterAPIService( | |||
| 			continue // skip this one
 | ||||
| 		} | ||||
| 
 | ||||
| 		if !ds.JSONData.Backend { | ||||
| 			continue // skip frontend only plugins
 | ||||
| 		} | ||||
| 
 | ||||
| 		builder, err = NewDataSourceAPIBuilder(ds.JSONData, | ||||
| 			pluginClient, | ||||
| 			datasources.GetDatasourceProvider(ds.JSONData), | ||||
|  |  | |||
|  | @ -7,29 +7,40 @@ import ( | |||
| 	"github.com/grafana/authlib/claims" | ||||
| 	"k8s.io/apiserver/pkg/authorization/authorizer" | ||||
| 
 | ||||
| 	iamv0 "github.com/grafana/grafana/pkg/apis/iam/v0alpha1" | ||||
| 	"github.com/grafana/grafana/pkg/registry/apis/iam/legacy" | ||||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol" | ||||
| 	gfauthorizer "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer" | ||||
| ) | ||||
| 
 | ||||
| func newLegacyAuthorizer(ac accesscontrol.AccessControl, store legacy.LegacyIdentityStore) (authorizer.Authorizer, claims.AccessClient) { | ||||
| 	client := accesscontrol.NewLegacyAccessClient(ac, accesscontrol.ResourceAuthorizerOptions{ | ||||
| 		Resource: "users", | ||||
| 		Attr:     "id", | ||||
| 		Mapping: map[string]string{ | ||||
| 			"get":  accesscontrol.ActionOrgUsersRead, | ||||
| 			"list": accesscontrol.ActionOrgUsersRead, | ||||
| 	client := accesscontrol.NewLegacyAccessClient( | ||||
| 		ac, | ||||
| 		accesscontrol.ResourceAuthorizerOptions{ | ||||
| 			Resource: iamv0.UserResourceInfo.GetName(), | ||||
| 			Attr:     "id", | ||||
| 			Mapping: map[string]string{ | ||||
| 				"get":  accesscontrol.ActionOrgUsersRead, | ||||
| 				"list": accesscontrol.ActionOrgUsersRead, | ||||
| 			}, | ||||
| 			Resolver: accesscontrol.ResourceResolverFunc(func(ctx context.Context, ns claims.NamespaceInfo, name string) ([]string, error) { | ||||
| 				res, err := store.GetUserInternalID(ctx, ns, legacy.GetUserInternalIDQuery{ | ||||
| 					UID: name, | ||||
| 				}) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				return []string{fmt.Sprintf("users:id:%d", res.ID)}, nil | ||||
| 			}), | ||||
| 		}, | ||||
| 		Resolver: accesscontrol.ResourceResolverFunc(func(ctx context.Context, ns claims.NamespaceInfo, name string) ([]string, error) { | ||||
| 			res, err := store.GetUserInternalID(ctx, ns, legacy.GetUserInternalIDQuery{ | ||||
| 				UID: name, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			return []string{fmt.Sprintf("users:id:%d", res.ID)}, nil | ||||
| 		}), | ||||
| 	}) | ||||
| 		accesscontrol.ResourceAuthorizerOptions{ | ||||
| 			Resource: "display", | ||||
| 			Unchecked: map[string]bool{ | ||||
| 				"get":  true, | ||||
| 				"list": true, | ||||
| 			}, | ||||
| 		}, | ||||
| 	) | ||||
| 
 | ||||
| 	return gfauthorizer.NewResourceAuthorizer(client), client | ||||
| } | ||||
|  |  | |||
|  | @ -24,7 +24,6 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/registry/apis/iam/user" | ||||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol" | ||||
| 	"github.com/grafana/grafana/pkg/services/apiserver/builder" | ||||
| 	"github.com/grafana/grafana/pkg/services/featuremgmt" | ||||
| 	"github.com/grafana/grafana/pkg/services/ssosettings" | ||||
| 	"github.com/grafana/grafana/pkg/storage/legacysql" | ||||
| ) | ||||
|  | @ -42,17 +41,11 @@ type IdentityAccessManagementAPIBuilder struct { | |||
| } | ||||
| 
 | ||||
| func RegisterAPIService( | ||||
| 	features featuremgmt.FeatureToggles, | ||||
| 	apiregistration builder.APIRegistrar, | ||||
| 	ssoService ssosettings.Service, | ||||
| 	sql db.DB, | ||||
| 	ac accesscontrol.AccessControl, | ||||
| ) (*IdentityAccessManagementAPIBuilder, error) { | ||||
| 	if !features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) { | ||||
| 		// skip registration unless opting into experimental apis
 | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	store := legacy.NewLegacySQLStores(legacysql.NewDatabaseProvider(sql)) | ||||
| 	authorizer, client := newLegacyAuthorizer(ac, store) | ||||
| 
 | ||||
|  | @ -114,9 +107,9 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge | |||
| 	storage[userResource.StoragePath()] = user.NewLegacyStore(b.store, b.accessClient) | ||||
| 	storage[userResource.StoragePath("teams")] = user.NewLegacyTeamMemberREST(b.store) | ||||
| 
 | ||||
| 	serviceaccountResource := iamv0.ServiceAccountResourceInfo | ||||
| 	storage[serviceaccountResource.StoragePath()] = serviceaccount.NewLegacyStore(b.store) | ||||
| 	storage[serviceaccountResource.StoragePath("tokens")] = serviceaccount.NewLegacyTokenREST(b.store) | ||||
| 	serviceAccountResource := iamv0.ServiceAccountResourceInfo | ||||
| 	storage[serviceAccountResource.StoragePath()] = serviceaccount.NewLegacyStore(b.store) | ||||
| 	storage[serviceAccountResource.StoragePath("tokens")] = serviceaccount.NewLegacyTokenREST(b.store) | ||||
| 
 | ||||
| 	if b.sso != nil { | ||||
| 		ssoResource := iamv0.SSOSettingResourceInfo | ||||
|  |  | |||
|  | @ -97,7 +97,7 @@ var cfg = &setting.Cfg{} | |||
| 
 | ||||
| func mapToTeamMember(m legacy.TeamMember) iamv0.TeamMember { | ||||
| 	return iamv0.TeamMember{ | ||||
| 		IdentityDisplay: iamv0.IdentityDisplay{ | ||||
| 		Display: iamv0.Display{ | ||||
| 			Identity: iamv0.IdentityRef{ | ||||
| 				Type: claims.TypeUser, | ||||
| 				Name: m.UserUID, | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ func NewLegacyDisplayREST(store legacy.LegacyIdentityStore) *LegacyDisplayREST { | |||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) New() runtime.Object { | ||||
| 	return &iamv0.IdentityDisplayResults{} | ||||
| 	return &iamv0.DisplayList{} | ||||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) Destroy() {} | ||||
|  | @ -45,8 +45,7 @@ func (r *LegacyDisplayREST) NamespaceScoped() bool { | |||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) GetSingularName() string { | ||||
| 	// not actually used anywhere, but required by SingularNameProvider
 | ||||
| 	return "identitydisplay" | ||||
| 	return "display" | ||||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) ProducesMIMETypes(verb string) []string { | ||||
|  | @ -54,11 +53,11 @@ func (r *LegacyDisplayREST) ProducesMIMETypes(verb string) []string { | |||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) ProducesObject(verb string) any { | ||||
| 	return &iamv0.IdentityDisplayResults{} | ||||
| 	return &iamv0.DisplayList{} | ||||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) ConnectMethods() []string { | ||||
| 	return []string{"GET"} | ||||
| 	return []string{http.MethodGet} | ||||
| } | ||||
| 
 | ||||
| func (r *LegacyDisplayREST) NewConnectOptions() (runtime.Object, bool, string) { | ||||
|  | @ -91,13 +90,13 @@ func (r *LegacyDisplayREST) Connect(ctx context.Context, name string, _ runtime. | |||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		rsp := &iamv0.IdentityDisplayResults{ | ||||
| 		rsp := &iamv0.DisplayList{ | ||||
| 			Keys:        keys.keys, | ||||
| 			InvalidKeys: keys.invalid, | ||||
| 			Display:     make([]iamv0.IdentityDisplay, 0, len(users.Users)+len(keys.disp)+1), | ||||
| 			Items:       make([]iamv0.Display, 0, len(users.Users)+len(keys.disp)+1), | ||||
| 		} | ||||
| 		for _, user := range users.Users { | ||||
| 			disp := iamv0.IdentityDisplay{ | ||||
| 			disp := iamv0.Display{ | ||||
| 				Identity: iamv0.IdentityRef{ | ||||
| 					Type: claims.TypeUser, | ||||
| 					Name: user.UID, | ||||
|  | @ -109,12 +108,12 @@ func (r *LegacyDisplayREST) Connect(ctx context.Context, name string, _ runtime. | |||
| 				disp.Identity.Type = claims.TypeServiceAccount | ||||
| 			} | ||||
| 			disp.AvatarURL = dtos.GetGravatarUrlWithDefault(fakeCfgForGravatar, user.Email, disp.DisplayName) | ||||
| 			rsp.Display = append(rsp.Display, disp) | ||||
| 			rsp.Items = append(rsp.Items, disp) | ||||
| 		} | ||||
| 
 | ||||
| 		// Append the constants here
 | ||||
| 		if len(keys.disp) > 0 { | ||||
| 			rsp.Display = append(rsp.Display, keys.disp...) | ||||
| 			rsp.Items = append(rsp.Items, keys.disp...) | ||||
| 		} | ||||
| 		responder.Object(200, rsp) | ||||
| 	}), nil | ||||
|  | @ -127,7 +126,7 @@ type dispKeys struct { | |||
| 	invalid []string | ||||
| 
 | ||||
| 	// For terminal keys, this is a constant
 | ||||
| 	disp []iamv0.IdentityDisplay | ||||
| 	disp []iamv0.Display | ||||
| } | ||||
| 
 | ||||
| func parseKeys(req []string) dispKeys { | ||||
|  | @ -148,7 +147,7 @@ func parseKeys(req []string) dispKeys { | |||
| 
 | ||||
| 			switch t { | ||||
| 			case claims.TypeAnonymous: | ||||
| 				keys.disp = append(keys.disp, iamv0.IdentityDisplay{ | ||||
| 				keys.disp = append(keys.disp, iamv0.Display{ | ||||
| 					Identity: iamv0.IdentityRef{ | ||||
| 						Type: t, | ||||
| 					}, | ||||
|  | @ -157,7 +156,7 @@ func parseKeys(req []string) dispKeys { | |||
| 				}) | ||||
| 				continue | ||||
| 			case claims.TypeAPIKey: | ||||
| 				keys.disp = append(keys.disp, iamv0.IdentityDisplay{ | ||||
| 				keys.disp = append(keys.disp, iamv0.Display{ | ||||
| 					Identity: iamv0.IdentityRef{ | ||||
| 						Type: t, | ||||
| 						Name: key, | ||||
|  | @ -167,7 +166,7 @@ func parseKeys(req []string) dispKeys { | |||
| 				}) | ||||
| 				continue | ||||
| 			case claims.TypeProvisioning: | ||||
| 				keys.disp = append(keys.disp, iamv0.IdentityDisplay{ | ||||
| 				keys.disp = append(keys.disp, iamv0.Display{ | ||||
| 					Identity: iamv0.IdentityRef{ | ||||
| 						Type: t, | ||||
| 					}, | ||||
|  | @ -184,7 +183,7 @@ func parseKeys(req []string) dispKeys { | |||
| 		id, err := strconv.ParseInt(key, 10, 64) | ||||
| 		if err == nil { | ||||
| 			if id == 0 { | ||||
| 				keys.disp = append(keys.disp, iamv0.IdentityDisplay{ | ||||
| 				keys.disp = append(keys.disp, iamv0.Display{ | ||||
| 					Identity: iamv0.IdentityRef{ | ||||
| 						Type: claims.TypeUser, | ||||
| 						Name: key, | ||||
|  |  | |||
|  | @ -27,6 +27,9 @@ func (r ResourceResolverFunc) Resolve(ctx context.Context, ns claims.NamespaceIn | |||
| type ResourceAuthorizerOptions struct { | ||||
| 	// Resource is the resource name in plural.
 | ||||
| 	Resource string | ||||
| 	// Unchecked is used to skip authorization checks for specified verbs.
 | ||||
| 	// This takes precedence over configured Mapping
 | ||||
| 	Unchecked map[string]bool | ||||
| 	// Attr is attribute used for resource scope. It's usually 'id' or 'uid'
 | ||||
| 	// depending on what is stored for the resource.
 | ||||
| 	Attr string | ||||
|  | @ -45,6 +48,9 @@ func NewLegacyAccessClient(ac AccessControl, opts ...ResourceAuthorizerOptions) | |||
| 	stored := map[string]ResourceAuthorizerOptions{} | ||||
| 
 | ||||
| 	for _, o := range opts { | ||||
| 		if o.Unchecked == nil { | ||||
| 			o.Unchecked = map[string]bool{} | ||||
| 		} | ||||
| 		if o.Mapping == nil { | ||||
| 			o.Mapping = map[string]string{} | ||||
| 		} | ||||
|  | @ -75,6 +81,11 @@ func (c *LegacyAccessClient) HasAccess(ctx context.Context, id claims.AuthInfo, | |||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	skip := opts.Unchecked[req.Verb] | ||||
| 	if skip { | ||||
| 		return true, nil | ||||
| 	} | ||||
| 
 | ||||
| 	action, ok := opts.Mapping[req.Verb] | ||||
| 	if !ok { | ||||
| 		return false, fmt.Errorf("missing action for %s %s", req.Verb, req.Resource) | ||||
|  |  | |||
|  | @ -103,6 +103,41 @@ func TestResourceAuthorizer_HasAccess(t *testing.T) { | |||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, true, ok) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("should skip authorization for configured verb", func(t *testing.T) { | ||||
| 		a := accesscontrol.NewLegacyAccessClient(ac, accesscontrol.ResourceAuthorizerOptions{ | ||||
| 			Resource: "dashboards", | ||||
| 			Attr:     "uid", | ||||
| 			Unchecked: map[string]bool{ | ||||
| 				"get": true, | ||||
| 			}, | ||||
| 			Mapping: map[string]string{ | ||||
| 				"create": "dashboards:create", | ||||
| 			}, | ||||
| 		}) | ||||
| 
 | ||||
| 		ident := newIdent(accesscontrol.Permission{}) | ||||
| 
 | ||||
| 		ok, err := a.HasAccess(context.Background(), ident, claims.AccessRequest{ | ||||
| 			Verb:      "get", | ||||
| 			Namespace: "default", | ||||
| 			Resource:  "dashboards", | ||||
| 			Name:      "1", | ||||
| 		}) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, true, ok) | ||||
| 
 | ||||
| 		ok, err = a.HasAccess(context.Background(), ident, claims.AccessRequest{ | ||||
| 			Verb:      "create", | ||||
| 			Namespace: "default", | ||||
| 			Resource:  "dashboards", | ||||
| 			Name:      "1", | ||||
| 		}) | ||||
| 
 | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, false, ok) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func newIdent(permissions ...accesscontrol.Permission) *identity.StaticRequester { | ||||
|  |  | |||
|  | @ -2,10 +2,9 @@ package correlations | |||
| 
 | ||||
| import ( | ||||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol" | ||||
| 	"github.com/grafana/grafana/pkg/services/datasources" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// ConfigurationPageAccess is used to protect the "Configure > correlations" tab access
 | ||||
| 	ConfigurationPageAccess = accesscontrol.EvalPermission(datasources.ActionRead) | ||||
| 	ConfigurationPageAccess = accesscontrol.EvalPermission(accesscontrol.ActionDatasourcesExplore) | ||||
| ) | ||||
|  |  | |||
|  | @ -1371,17 +1371,6 @@ var ( | |||
| 			Owner:       awsDatasourcesSquad, | ||||
| 			Expression:  "true", | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:              "bodyScrolling", | ||||
| 			Description:       "Adjusts Page to make body the scrollable element", | ||||
| 			Stage:             FeatureStagePublicPreview, | ||||
| 			Owner:             grafanaFrontendPlatformSquad, | ||||
| 			Expression:        "false", // enabled by default
 | ||||
| 			FrontendOnly:      true, | ||||
| 			AllowSelfServe:    true, | ||||
| 			HideFromDocs:      true, | ||||
| 			HideFromAdminPage: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:         "cloudwatchMetricInsightsCrossAccount", | ||||
| 			Description:  "Enables cross account observability for Cloudwatch Metric Insights query builder", | ||||
|  |  | |||
|  | @ -180,7 +180,6 @@ passScopeToDashboardApi,experimental,@grafana/dashboards-squad,false,false,false | |||
| alertingApiServer,experimental,@grafana/alerting-squad,false,true,false | ||||
| dashboardRestoreUI,experimental,@grafana/grafana-frontend-platform,false,false,false | ||||
| cloudWatchRoundUpEndTime,GA,@grafana/aws-datasources,false,false,false | ||||
| bodyScrolling,preview,@grafana/grafana-frontend-platform,false,false,true | ||||
| cloudwatchMetricInsightsCrossAccount,preview,@grafana/aws-datasources,false,false,true | ||||
| prometheusAzureOverrideAudience,deprecated,@grafana/partner-datasources,false,false,false | ||||
| alertingFilterV2,experimental,@grafana/alerting-squad,false,false,false | ||||
|  |  | |||
| 
 | 
|  | @ -731,10 +731,6 @@ const ( | |||
| 	// Round up end time for metric queries to the next minute to avoid missing data
 | ||||
| 	FlagCloudWatchRoundUpEndTime = "cloudWatchRoundUpEndTime" | ||||
| 
 | ||||
| 	// FlagBodyScrolling
 | ||||
| 	// Adjusts Page to make body the scrollable element
 | ||||
| 	FlagBodyScrolling = "bodyScrolling" | ||||
| 
 | ||||
| 	// FlagCloudwatchMetricInsightsCrossAccount
 | ||||
| 	// Enables cross account observability for Cloudwatch Metric Insights query builder
 | ||||
| 	FlagCloudwatchMetricInsightsCrossAccount = "cloudwatchMetricInsightsCrossAccount" | ||||
|  |  | |||
|  | @ -595,6 +595,7 @@ | |||
|         "name": "bodyScrolling", | ||||
|         "resourceVersion": "1721723807004", | ||||
|         "creationTimestamp": "2024-07-01T10:28:39Z", | ||||
|         "deletionTimestamp": "2024-09-24T09:17:00Z", | ||||
|         "annotations": { | ||||
|           "grafana.app/updatedTimestamp": "2024-07-23 08:36:47.004393 +0000 UTC" | ||||
|         } | ||||
|  |  | |||
|  | @ -22,7 +22,6 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/services/datasources" | ||||
| 	"github.com/grafana/grafana/pkg/services/ngalert/models" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
| 	"github.com/grafana/grafana/pkg/util" | ||||
| ) | ||||
| 
 | ||||
| var logger = log.New("ngalert.eval") | ||||
|  | @ -705,13 +704,6 @@ func evaluateExecutionResult(execResults ExecutionResults, ts time.Time) Results | |||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// The query service returns instant vectors from prometheus as scalars. We need to handle them accordingly.
 | ||||
| 		if val, ok := scalarInstantVector(f); ok { | ||||
| 			r := buildResult(f, val, ts) | ||||
| 			evalResults = append(evalResults, r) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if len(f.TypeIndices(data.FieldTypeTime, data.FieldTypeNullableTime)) > 0 { | ||||
| 			appendErrRes(&invalidEvalResultFormatError{refID: f.RefID, reason: "looks like time series data, only reduced data can be alerted on."}) | ||||
| 			continue | ||||
|  | @ -789,23 +781,6 @@ func buildResult(f *data.Frame, val *float64, ts time.Time) Result { | |||
| 	return r | ||||
| } | ||||
| 
 | ||||
| func scalarInstantVector(f *data.Frame) (*float64, bool) { | ||||
| 	if len(f.Fields) != 2 { | ||||
| 		return nil, false | ||||
| 	} | ||||
| 	if f.Fields[0].Len() > 1 || (f.Fields[0].Type() != data.FieldTypeNullableTime && f.Fields[0].Type() != data.FieldTypeTime) { | ||||
| 		return nil, false | ||||
| 	} | ||||
| 	switch f.Fields[1].Type() { | ||||
| 	case data.FieldTypeFloat64: | ||||
| 		return util.Pointer(f.Fields[1].At(0).(float64)), true | ||||
| 	case data.FieldTypeNullableFloat64: | ||||
| 		return f.Fields[1].At(0).(*float64), true | ||||
| 	default: | ||||
| 		return nil, true | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AsDataFrame forms the EvalResults in Frame suitable for displaying in the table panel of the front end.
 | ||||
| // It displays one row per alert instance, with a column for each label and one for the alerting state.
 | ||||
| func (evalResults Results) AsDataFrame() data.Frame { | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ package eval | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
|  | @ -63,52 +62,6 @@ func TestEvaluateExecutionResult(t *testing.T) { | |||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			desc: "query service dataframe works as instant vector", | ||||
| 			execResults: ExecutionResults{ | ||||
| 				Condition: func() []*data.Frame { | ||||
| 					f := data.NewFrame("", | ||||
| 						data.NewField("", nil, []*time.Time{util.Pointer(time.Now())}), | ||||
| 						data.NewField("", nil, []*float64{util.Pointer(0.0)}), | ||||
| 					) | ||||
| 					f.Meta = &data.FrameMeta{ | ||||
| 						Custom: map[string]any{ | ||||
| 							"resultType": "scalar", | ||||
| 						}, | ||||
| 					} | ||||
| 					return []*data.Frame{f} | ||||
| 				}(), | ||||
| 			}, | ||||
| 			expectResultLength: 1, | ||||
| 			expectResults: Results{ | ||||
| 				{ | ||||
| 					State: Normal, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			desc: "query service dataframe works as instant vector when alerting", | ||||
| 			execResults: ExecutionResults{ | ||||
| 				Condition: func() []*data.Frame { | ||||
| 					f := data.NewFrame("", | ||||
| 						data.NewField("", nil, []*time.Time{util.Pointer(time.Now())}), | ||||
| 						data.NewField("", nil, []*float64{util.Pointer(1.0)}), | ||||
| 					) | ||||
| 					f.Meta = &data.FrameMeta{ | ||||
| 						Custom: map[string]any{ | ||||
| 							"resultType": "scalar", | ||||
| 						}, | ||||
| 					} | ||||
| 					return []*data.Frame{f} | ||||
| 				}(), | ||||
| 			}, | ||||
| 			expectResultLength: 1, | ||||
| 			expectResults: Results{ | ||||
| 				{ | ||||
| 					State: Alerting, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			desc: "nil value single instance is single a NoData state result", | ||||
| 			execResults: ExecutionResults{ | ||||
|  | @ -1343,76 +1296,6 @@ func TestCreate(t *testing.T) { | |||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestQueryServiceResponse(t *testing.T) { | ||||
| 	data := ` | ||||
| { | ||||
|     "results": { | ||||
|         "A": { | ||||
|             "status": 200, | ||||
|             "frames": [ | ||||
|                 { | ||||
|                     "schema": { | ||||
|                         "refId": "A", | ||||
|                         "meta": { | ||||
|                             "type": "numeric-multi", | ||||
|                             "typeVersion": [ | ||||
|                                 0, | ||||
|                                 1 | ||||
|                             ], | ||||
|                             "custom": { | ||||
|                                 "resultType": "scalar" | ||||
|                             }, | ||||
|                             "executedQueryString": "Expr: 1\nStep: 15s" | ||||
|                         }, | ||||
|                         "fields": [ | ||||
|                             { | ||||
|                                 "name": "Time", | ||||
|                                 "type": "time", | ||||
|                                 "typeInfo": { | ||||
|                                     "frame": "time.Time" | ||||
|                                 }, | ||||
|                                 "config": { | ||||
|                                     "interval": 15000 | ||||
|                                 } | ||||
|                             }, | ||||
|                             { | ||||
|                                 "name": "Value", | ||||
|                                 "type": "number", | ||||
|                                 "typeInfo": { | ||||
|                                     "frame": "float64" | ||||
|                                 }, | ||||
|                                 "labels": {}, | ||||
|                                 "config": { | ||||
|                                     "displayNameFromDS": "1" | ||||
|                                 } | ||||
|                             } | ||||
|                         ] | ||||
|                     }, | ||||
|                     "data": { | ||||
|                         "values": [ | ||||
|                             [ | ||||
|                                 1719855251019 | ||||
|                             ], | ||||
|                             [ | ||||
|                                 1 | ||||
|                             ] | ||||
|                         ] | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ` | ||||
| 	var s backend.QueryDataResponse | ||||
| 	err := json.Unmarshal([]byte(data), &s) | ||||
| 	require.NoError(t, err) | ||||
| 	res := EvaluateAlert(&s, models.Condition{Condition: "A"}, time.Time{}) | ||||
| 
 | ||||
| 	require.Equal(t, 1, len(res)) | ||||
| 	require.Equal(t, Alerting, res[0].State) | ||||
| } | ||||
| 
 | ||||
| type fakeExpressionService struct { | ||||
| 	hook      func(ctx context.Context, now time.Time, pipeline expr.DataPipeline) (*backend.QueryDataResponse, error) | ||||
| 	buildHook func(req *expr.Request) (expr.DataPipeline, error) | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ package identity | |||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/services/featuremgmt" | ||||
|  | @ -30,22 +29,6 @@ func TestMain(m *testing.M) { | |||
| 	testsuite.Run(m) | ||||
| } | ||||
| 
 | ||||
| func TestIntegrationRequiresDevMode(t *testing.T) { | ||||
| 	if testing.Short() { | ||||
| 		t.Skip("skipping integration test") | ||||
| 	} | ||||
| 	helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ | ||||
| 		AppModeProduction: true, // should fail
 | ||||
| 		DisableAnonymous:  true, | ||||
| 		EnableFeatureToggles: []string{ | ||||
| 			featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, // Required to start the example service
 | ||||
| 		}, | ||||
| 	}) | ||||
| 
 | ||||
| 	_, err := helper.NewDiscoveryClient().ServerResourcesForGroupVersion("iam.grafana.app/v0alpha1") | ||||
| 	require.Error(t, err) | ||||
| } | ||||
| 
 | ||||
| func TestIntegrationIdentity(t *testing.T) { | ||||
| 	if testing.Short() { | ||||
| 		t.Skip("skipping integration test") | ||||
|  | @ -102,7 +85,6 @@ func TestIntegrationIdentity(t *testing.T) { | |||
| 
 | ||||
| 		// Get just the specs (avoids values that change with each deployment)
 | ||||
| 		found = teamClient.SpecJSON(rsp) | ||||
| 		// fmt.Printf("%s", found) // NOTE the first value does not have an email or login
 | ||||
| 		require.JSONEq(t, `[ | ||||
| 			{}, | ||||
| 			{ | ||||
|  | @ -130,7 +112,6 @@ func TestIntegrationIdentity(t *testing.T) { | |||
| 
 | ||||
| 		// Get just the specs (avoids values that change with each deployment)
 | ||||
| 		found = teamClient.SpecJSON(rsp) | ||||
| 		fmt.Printf("%s", found) // NOTE the first value does not have an email or login
 | ||||
| 		require.JSONEq(t, `[ | ||||
| 			{ | ||||
| 				"email": "admin-3", | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import classNames from 'classnames'; | |||
| import { PropsWithChildren, useEffect } from 'react'; | ||||
| 
 | ||||
| import { GrafanaTheme2 } from '@grafana/data'; | ||||
| import { config, locationSearchToObject, locationService } from '@grafana/runtime'; | ||||
| import { locationSearchToObject, locationService } from '@grafana/runtime'; | ||||
| import { useStyles2, LinkButton, useTheme2 } from '@grafana/ui'; | ||||
| import { useGrafana } from 'app/core/context/GrafanaContext'; | ||||
| import { useMediaQueryChange } from 'app/core/hooks/useMediaQueryChange'; | ||||
|  | @ -121,10 +121,8 @@ export function AppChrome({ children }: Props) { | |||
|           )} | ||||
|           <main | ||||
|             className={cx(styles.pageContainer, { | ||||
|               [styles.pageContainerMenuDocked]: | ||||
|                 config.featureToggles.bodyScrolling && (menuDockedAndOpen || isScopesDashboardsOpen), | ||||
|               [styles.pageContainerMenuDockedScopes]: | ||||
|                 config.featureToggles.bodyScrolling && menuDockedAndOpen && isScopesDashboardsOpen, | ||||
|               [styles.pageContainerMenuDocked]: menuDockedAndOpen || isScopesDashboardsOpen, | ||||
|               [styles.pageContainerMenuDockedScopes]: menuDockedAndOpen && isScopesDashboardsOpen, | ||||
|             })} | ||||
|             id="pageContent" | ||||
|           > | ||||
|  | @ -148,7 +146,7 @@ const getStyles = (theme: GrafanaTheme2, searchBarHidden: boolean) => { | |||
|       flexDirection: 'column', | ||||
|       paddingTop: TOP_BAR_LEVEL_HEIGHT * 2, | ||||
|       flexGrow: 1, | ||||
|       height: config.featureToggles.bodyScrolling ? 'auto' : '100%', | ||||
|       height: 'auto', | ||||
|     }), | ||||
|     contentNoSearchBar: css({ | ||||
|       paddingTop: TOP_BAR_LEVEL_HEIGHT, | ||||
|  | @ -167,27 +165,17 @@ const getStyles = (theme: GrafanaTheme2, searchBarHidden: boolean) => { | |||
|           display: 'block', | ||||
|         }, | ||||
|       }, | ||||
|       config.featureToggles.bodyScrolling | ||||
|         ? { | ||||
|             position: 'fixed', | ||||
|             height: `calc(100% - ${searchBarHidden ? TOP_BAR_LEVEL_HEIGHT : TOP_BAR_LEVEL_HEIGHT * 2}px)`, | ||||
|             zIndex: 2, | ||||
|           } | ||||
|         : { | ||||
|             zIndex: theme.zIndex.navbarFixed, | ||||
|           } | ||||
|     ), | ||||
|     scopesDashboardsContainer: css( | ||||
|       config.featureToggles.bodyScrolling | ||||
|         ? { | ||||
|             position: 'fixed', | ||||
|             height: `calc(100% - ${searchBarHidden ? TOP_BAR_LEVEL_HEIGHT : TOP_BAR_LEVEL_HEIGHT * 2}px)`, | ||||
|             zIndex: 1, | ||||
|           } | ||||
|         : { | ||||
|             zIndex: theme.zIndex.navbarFixed, | ||||
|           } | ||||
|       { | ||||
|         position: 'fixed', | ||||
|         height: `calc(100% - ${searchBarHidden ? TOP_BAR_LEVEL_HEIGHT : TOP_BAR_LEVEL_HEIGHT * 2}px)`, | ||||
|         zIndex: 2, | ||||
|       } | ||||
|     ), | ||||
|     scopesDashboardsContainer: css({ | ||||
|       position: 'fixed', | ||||
|       height: `calc(100% - ${searchBarHidden ? TOP_BAR_LEVEL_HEIGHT : TOP_BAR_LEVEL_HEIGHT * 2}px)`, | ||||
|       zIndex: 1, | ||||
|     }), | ||||
|     scopesDashboardsContainerDocked: css({ | ||||
|       left: MENU_WIDTH, | ||||
|     }), | ||||
|  | @ -200,49 +188,24 @@ const getStyles = (theme: GrafanaTheme2, searchBarHidden: boolean) => { | |||
|       background: theme.colors.background.primary, | ||||
|       flexDirection: 'column', | ||||
|     }), | ||||
|     panes: css( | ||||
|       { | ||||
|         display: 'flex', | ||||
|         flexDirection: 'column', | ||||
|         flexGrow: 1, | ||||
|         label: 'page-panes', | ||||
|       }, | ||||
|       !config.featureToggles.bodyScrolling && { | ||||
|         height: '100%', | ||||
|         minHeight: 0, | ||||
|         width: '100%', | ||||
|         [theme.breakpoints.up('md')]: { | ||||
|           flexDirection: 'row', | ||||
|         }, | ||||
|       } | ||||
|     ), | ||||
|     panes: css({ | ||||
|       display: 'flex', | ||||
|       flexDirection: 'column', | ||||
|       flexGrow: 1, | ||||
|       label: 'page-panes', | ||||
|     }), | ||||
|     pageContainerMenuDocked: css({ | ||||
|       paddingLeft: MENU_WIDTH, | ||||
|     }), | ||||
|     pageContainerMenuDockedScopes: css({ | ||||
|       paddingLeft: `calc(${MENU_WIDTH} * 2)`, | ||||
|     }), | ||||
|     pageContainer: css( | ||||
|       { | ||||
|         label: 'page-container', | ||||
|         display: 'flex', | ||||
|         flexDirection: 'column', | ||||
|         flexGrow: 1, | ||||
|       }, | ||||
|       !config.featureToggles.bodyScrolling && { | ||||
|         minHeight: 0, | ||||
|         minWidth: 0, | ||||
|         overflow: 'auto', | ||||
|         '@media print': { | ||||
|           overflow: 'visible', | ||||
|         }, | ||||
|         '@page': { | ||||
|           margin: 0, | ||||
|           size: 'auto', | ||||
|           padding: 0, | ||||
|         }, | ||||
|       } | ||||
|     ), | ||||
|     pageContainer: css({ | ||||
|       label: 'page-container', | ||||
|       display: 'flex', | ||||
|       flexDirection: 'column', | ||||
|       flexGrow: 1, | ||||
|     }), | ||||
|     skipLink: css({ | ||||
|       position: 'fixed', | ||||
|       top: -1000, | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ import { useEffect, useState } from 'react'; | |||
| import * as React from 'react'; | ||||
| 
 | ||||
| import { GrafanaTheme2 } from '@grafana/data'; | ||||
| import { config } from '@grafana/runtime'; | ||||
| import { useStyles2 } from '@grafana/ui'; | ||||
| 
 | ||||
| import { Branding } from '../Branding/Branding'; | ||||
|  | @ -37,9 +36,7 @@ export const LoginLayout = ({ children, branding, isChangingPassword }: React.Pr | |||
| 
 | ||||
|   return ( | ||||
|     <Branding.LoginBackground | ||||
|       className={cx(loginStyles.container, startAnim && loginStyles.loginAnim, branding?.loginBackground, { | ||||
|         [loginStyles.containerBodyScrolling]: config.featureToggles.bodyScrolling, | ||||
|       })} | ||||
|       className={cx(loginStyles.container, startAnim && loginStyles.loginAnim, branding?.loginBackground)} | ||||
|     > | ||||
|       <div className={loginStyles.loginMain}> | ||||
|         <div className={cx(loginStyles.loginContent, loginBoxBackground, 'login-content-box')}> | ||||
|  | @ -89,6 +86,7 @@ export const getLoginStyles = (theme: GrafanaTheme2) => { | |||
|       minHeight: '100%', | ||||
|       backgroundPosition: 'center', | ||||
|       backgroundRepeat: 'no-repeat', | ||||
|       flex: 1, | ||||
|       minWidth: '100%', | ||||
|       marginLeft: 0, | ||||
|       display: 'flex', | ||||
|  | @ -96,9 +94,6 @@ export const getLoginStyles = (theme: GrafanaTheme2) => { | |||
|       alignItems: 'center', | ||||
|       justifyContent: 'center', | ||||
|     }), | ||||
|     containerBodyScrolling: css({ | ||||
|       flex: 1, | ||||
|     }), | ||||
|     loginAnim: css({ | ||||
|       ['&:before']: { | ||||
|         opacity: 1, | ||||
|  |  | |||
|  | @ -1,9 +1,4 @@ | |||
| import { css, cx } from '@emotion/css'; | ||||
| import { useEffect, useRef } from 'react'; | ||||
| 
 | ||||
| import { config } from '@grafana/runtime'; | ||||
| import { useStyles2 } from '@grafana/ui'; | ||||
| 
 | ||||
| export interface Props { | ||||
|   children: React.ReactNode; | ||||
|   onSetScrollRef?: (ref: ScrollRefElement) => void; | ||||
|  | @ -16,30 +11,16 @@ export interface ScrollRefElement { | |||
| } | ||||
| 
 | ||||
| // Shim to provide API-compatibility for Page's scroll-related props
 | ||||
| // when bodyScrolling is enabled, this is a no-op
 | ||||
| // TODO remove this shim completely when bodyScrolling is enabled
 | ||||
| export default function NativeScrollbar({ children, onSetScrollRef, divId }: Props) { | ||||
|   const styles = useStyles2(getStyles); | ||||
|   const ref = useRef<HTMLDivElement>(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (config.featureToggles.bodyScrolling && onSetScrollRef) { | ||||
|     if (onSetScrollRef) { | ||||
|       onSetScrollRef(new DivScrollElement(document.documentElement)); | ||||
|     } | ||||
| 
 | ||||
|     if (!config.featureToggles.bodyScrolling && ref.current && onSetScrollRef) { | ||||
|       onSetScrollRef(new DivScrollElement(ref.current)); | ||||
|     } | ||||
|   }, [ref, onSetScrollRef]); | ||||
| 
 | ||||
|   return config.featureToggles.bodyScrolling ? ( | ||||
|     children | ||||
|   ) : ( | ||||
|     // Set the .scrollbar-view class to help e2e tests find this, like in CustomScrollbar
 | ||||
|     <div ref={ref} className={cx(styles.nativeScrollbars, 'scrollbar-view')} id={divId}> | ||||
|       {children} | ||||
|     </div> | ||||
|   ); | ||||
|   return children; | ||||
| } | ||||
| 
 | ||||
| class DivScrollElement { | ||||
|  | @ -61,17 +42,3 @@ class DivScrollElement { | |||
|     this.element.scrollTo(x, y); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function getStyles() { | ||||
|   return { | ||||
|     nativeScrollbars: css({ | ||||
|       label: 'native-scroll-container', | ||||
|       minHeight: `calc(100% + 0px)`, // I don't know, just copied from custom scrollbars
 | ||||
|       maxHeight: `calc(100% + 0px)`, // I don't know, just copied from custom scrollbars
 | ||||
|       display: 'flex', | ||||
|       flexDirection: 'column', | ||||
|       flexGrow: 1, | ||||
|       overflow: 'auto', | ||||
|     }), | ||||
|   }; | ||||
| } | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ import { css, cx } from '@emotion/css'; | |||
| import { useLayoutEffect } from 'react'; | ||||
| 
 | ||||
| import { GrafanaTheme2, PageLayoutType } from '@grafana/data'; | ||||
| import { config } from '@grafana/runtime'; | ||||
| import { useStyles2 } from '@grafana/ui'; | ||||
| import { useGrafana } from 'app/core/context/GrafanaContext'; | ||||
| 
 | ||||
|  | @ -94,24 +93,13 @@ Page.Contents = PageContents; | |||
| 
 | ||||
| const getStyles = (theme: GrafanaTheme2) => { | ||||
|   return { | ||||
|     wrapper: css( | ||||
|       config.featureToggles.bodyScrolling | ||||
|         ? { | ||||
|             label: 'page-wrapper', | ||||
|             display: 'flex', | ||||
|             flex: '1 1 0', | ||||
|             flexDirection: 'column', | ||||
|             position: 'relative', | ||||
|           } | ||||
|         : { | ||||
|             label: 'page-wrapper', | ||||
|             height: '100%', | ||||
|             display: 'flex', | ||||
|             flex: '1 1 0', | ||||
|             flexDirection: 'column', | ||||
|             minHeight: 0, | ||||
|           } | ||||
|     ), | ||||
|     wrapper: css({ | ||||
|       label: 'page-wrapper', | ||||
|       display: 'flex', | ||||
|       flex: '1 1 0', | ||||
|       flexDirection: 'column', | ||||
|       position: 'relative', | ||||
|     }), | ||||
|     pageContent: css({ | ||||
|       label: 'page-content', | ||||
|       flexGrow: 1, | ||||
|  |  | |||
|  | @ -23,11 +23,7 @@ export interface PageProps extends HTMLAttributes<HTMLDivElement> { | |||
|   subTitle?: React.ReactNode; | ||||
|   /** Control the page layout. */ | ||||
|   layout?: PageLayoutType; | ||||
|   /** | ||||
|    * TODO: Not sure we should deprecated it given the sidecar project? | ||||
|    * @deprecated this will be removed when bodyScrolling is enabled by default | ||||
|    * Can be used to get the scroll container element to access scroll position | ||||
|    * */ | ||||
|   /** Can be used to get the scroll container element to access scroll position */ | ||||
|   onSetScrollRef?: (ref: ScrollRefElement) => void; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { createContext, useCallback, useContext } from 'react'; | ||||
| 
 | ||||
| import { GrafanaConfig } from '@grafana/data'; | ||||
| import { LocationService, locationService, BackendSrv, config } from '@grafana/runtime'; | ||||
| import { LocationService, locationService, BackendSrv } from '@grafana/runtime'; | ||||
| 
 | ||||
| import { AppChromeService } from '../components/AppChrome/AppChromeService'; | ||||
| import { NewFrontendAssetsChecker } from '../services/NewFrontendAssetsChecker'; | ||||
|  | @ -48,7 +48,7 @@ export function useChromeHeaderHeight() { | |||
|   const { chrome } = useGrafana(); | ||||
|   const { kioskMode, searchBarHidden, chromeless } = chrome.useState(); | ||||
| 
 | ||||
|   if (kioskMode || chromeless || !config.featureToggles.bodyScrolling) { | ||||
|   if (kioskMode || chromeless) { | ||||
|     return 0; | ||||
|   } else if (searchBarHidden) { | ||||
|     return SINGLE_HEADER_BAR_HEIGHT; | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import { css, cx } from '@emotion/css'; | ||||
| import { css } from '@emotion/css'; | ||||
| 
 | ||||
| import { GrafanaTheme2 } from '@grafana/data'; | ||||
| import { config } from '@grafana/runtime'; | ||||
| import { useStyles2 } from '@grafana/ui'; | ||||
| 
 | ||||
| import { BouncingLoader } from '../components/BouncingLoader/BouncingLoader'; | ||||
|  | @ -10,12 +9,7 @@ export function GrafanaRouteLoading() { | |||
|   const styles = useStyles2(getStyles); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       className={cx({ | ||||
|         [styles.loadingPage]: !config.featureToggles.bodyScrolling, | ||||
|         [styles.loadingPageBodyScrolling]: config.featureToggles.bodyScrolling, | ||||
|       })} | ||||
|     > | ||||
|     <div className={styles.loadingPage}> | ||||
|       <BouncingLoader /> | ||||
|     </div> | ||||
|   ); | ||||
|  | @ -23,14 +17,6 @@ export function GrafanaRouteLoading() { | |||
| 
 | ||||
| const getStyles = (theme: GrafanaTheme2) => ({ | ||||
|   loadingPage: css({ | ||||
|     backgroundColor: theme.colors.background.primary, | ||||
|     height: '100%', | ||||
|     flexDrection: 'column', | ||||
|     display: 'flex', | ||||
|     justifyContent: 'center', | ||||
|     alignItems: 'center', | ||||
|   }), | ||||
|   loadingPageBodyScrolling: css({ | ||||
|     backgroundColor: theme.colors.background.primary, | ||||
|     flex: 1, | ||||
|     flexDrection: 'column', | ||||
|  |  | |||
|  | @ -1,4 +1,7 @@ | |||
| import { Location } from 'history'; | ||||
| 
 | ||||
| import { locationService, setBackendSrv, BackendSrv } from '@grafana/runtime'; | ||||
| import { playlistSrv } from 'app/features/playlist/PlaylistSrv'; | ||||
| 
 | ||||
| import { NewFrontendAssetsChecker } from './NewFrontendAssetsChecker'; | ||||
| 
 | ||||
|  | @ -46,4 +49,28 @@ describe('NewFrontendAssetsChecker', () => { | |||
| 
 | ||||
|     expect(backendApiGet).toHaveBeenCalledTimes(2); | ||||
|   }); | ||||
| 
 | ||||
|   it('should skip reloading if we are playing a playlist', () => { | ||||
|     const checker = new NewFrontendAssetsCheckerExposedLocationUpdate(); | ||||
|     const reloadMock = jest.fn(); | ||||
|     checker.reloadIfUpdateDetected = reloadMock; | ||||
|     playlistSrv.state.isPlaying = true; | ||||
|     checker.doLocationUpdated({ hash: 'foo', pathname: '/d/dashboarduid', state: {}, search: '' }); | ||||
|     expect(reloadMock).not.toHaveBeenCalled(); | ||||
|     playlistSrv.state.isPlaying = false; | ||||
|   }); | ||||
| 
 | ||||
|   it('should reload if we are accessing a dashboard', () => { | ||||
|     const checker = new NewFrontendAssetsCheckerExposedLocationUpdate(); | ||||
|     const reloadMock = jest.fn(); | ||||
|     checker.reloadIfUpdateDetected = reloadMock; | ||||
|     checker.doLocationUpdated({ hash: 'foo', pathname: '/d/dashboarduid', state: {}, search: '' }); | ||||
|     expect(reloadMock).toHaveBeenCalled(); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| class NewFrontendAssetsCheckerExposedLocationUpdate extends NewFrontendAssetsChecker { | ||||
|   public doLocationUpdated(location: Location) { | ||||
|     this.locationUpdated(location); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ import { Location } from 'history'; | |||
| import { isEqual } from 'lodash'; | ||||
| 
 | ||||
| import { getBackendSrv, getGrafanaLiveSrv, locationService, reportInteraction } from '@grafana/runtime'; | ||||
| import { playlistSrv } from 'app/features/playlist/PlaylistSrv'; | ||||
| 
 | ||||
| export class NewFrontendAssetsChecker { | ||||
|   private hasUpdates = false; | ||||
|  | @ -35,7 +36,7 @@ export class NewFrontendAssetsChecker { | |||
|   /** | ||||
|    * Tries to detect some navigation events where it's safe to trigger a reload | ||||
|    */ | ||||
|   private locationUpdated(location: Location) { | ||||
|   protected locationUpdated(location: Location) { | ||||
|     if (this.prevLocationPath === location.pathname) { | ||||
|       return; | ||||
|     } | ||||
|  | @ -46,8 +47,8 @@ export class NewFrontendAssetsChecker { | |||
|     if (newLocationSegments[1] === '/' && this.prevLocationPath !== '/') { | ||||
|       this.reloadIfUpdateDetected(); | ||||
|     } | ||||
|     // Moving to dashboard (or changing dashboards)
 | ||||
|     else if (newLocationSegments[1] === 'd') { | ||||
|     // Moving to dashboard (or changing dashboards, except when we're playing a playlist)
 | ||||
|     else if (newLocationSegments[1] === 'd' && !playlistSrv.state.isPlaying) { | ||||
|       this.reloadIfUpdateDetected(); | ||||
|     } | ||||
|     // Track potential page change
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ import { css } from '@emotion/css'; | |||
| import * as React from 'react'; | ||||
| 
 | ||||
| import { GrafanaTheme2 } from '@grafana/data'; | ||||
| import { config, useChromeHeaderHeight } from '@grafana/runtime'; | ||||
| import { useChromeHeaderHeight } from '@grafana/runtime'; | ||||
| import { Icon, Input, useStyles2 } from '@grafana/ui'; | ||||
| import { t } from 'app/core/internationalization'; | ||||
| 
 | ||||
|  | @ -28,7 +28,7 @@ export interface Props { | |||
| 
 | ||||
| export const Search = ({ onChange, value }: Props) => { | ||||
|   const chromeHeaderHeight = useChromeHeaderHeight(); | ||||
|   const styles = useStyles2(getStyles, config.featureToggles.bodyScrolling ? (chromeHeaderHeight ?? 0) : 0); | ||||
|   const styles = useStyles2(getStyles, chromeHeaderHeight ?? 0); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={styles.searchContainer}> | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ import { css, cx } from '@emotion/css'; | |||
| 
 | ||||
| import { GrafanaTheme2 } from '@grafana/data'; | ||||
| import { selectors } from '@grafana/e2e-selectors'; | ||||
| import { config } from '@grafana/runtime'; | ||||
| import { SceneComponentProps } from '@grafana/scenes'; | ||||
| import { Button, ToolbarButton, useStyles2 } from '@grafana/ui'; | ||||
| 
 | ||||
|  | @ -35,9 +34,7 @@ export function PanelEditorRenderer({ model }: SceneComponentProps<PanelEditor>) | |||
|       <NavToolbarActions dashboard={dashboard} /> | ||||
|       <div | ||||
|         {...containerProps} | ||||
|         className={cx(containerProps.className, { | ||||
|           [styles.content]: config.featureToggles.bodyScrolling, | ||||
|         })} | ||||
|         className={cx(containerProps.className, styles.content)} | ||||
|         data-testid={selectors.components.PanelEditor.General.content} | ||||
|       > | ||||
|         <div {...primaryProps} className={cx(primaryProps.className, styles.body)}> | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ export const PanelOptions = React.memo<Props>(({ vizManager, searchQuery, listMo | |||
|       instanceState: _pluginInstanceState, | ||||
|     }); | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
|   }, [panel, options, fieldConfig, _pluginInstanceState]); | ||||
|   }, [data, panel, options, fieldConfig, _pluginInstanceState]); | ||||
| 
 | ||||
|   const libraryPanelOptions = useMemo(() => { | ||||
|     if (panel instanceof VizPanel && isLibraryPanel(panel)) { | ||||
|  |  | |||
|  | @ -66,23 +66,15 @@ describe('DashboardControls', () => { | |||
|       expect(scene._urlSync.getKeys()).toEqual(['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks']); | ||||
|     }); | ||||
| 
 | ||||
|     it('should return url state', () => { | ||||
|     it('should not return url state for hide flags', () => { | ||||
|       const scene = buildTestScene(); | ||||
|       expect(scene.getUrlState()).toEqual({ | ||||
|         '_dash.hideTimePicker': undefined, | ||||
|         '_dash.hideVariables': undefined, | ||||
|         '_dash.hideLinks': undefined, | ||||
|       }); | ||||
|       expect(scene.getUrlState()).toEqual({}); | ||||
|       scene.setState({ | ||||
|         hideTimeControls: true, | ||||
|         hideVariableControls: true, | ||||
|         hideLinksControls: true, | ||||
|       }); | ||||
|       expect(scene.getUrlState()).toEqual({ | ||||
|         '_dash.hideTimePicker': 'true', | ||||
|         '_dash.hideVariables': 'true', | ||||
|         '_dash.hideLinks': 'true', | ||||
|       }); | ||||
|       expect(scene.getUrlState()).toEqual({}); | ||||
|     }); | ||||
| 
 | ||||
|     it('should update from url', () => { | ||||
|  | @ -114,19 +106,16 @@ describe('DashboardControls', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('should not call setState if no changes', () => { | ||||
|       const scene = buildTestScene(); | ||||
|       const scene = buildTestScene({ hideTimeControls: true, hideVariableControls: true, hideLinksControls: true }); | ||||
|       const setState = jest.spyOn(scene, 'setState'); | ||||
| 
 | ||||
|       scene.updateFromUrl({ | ||||
|         '_dash.hideTimePicker': 'true', | ||||
|         '_dash.hideVariables': 'true', | ||||
|         '_dash.hideLinks': 'true', | ||||
|       }); | ||||
|       scene.updateFromUrl({ | ||||
|         '_dash.hideTimePicker': 'true', | ||||
|         '_dash.hideVariables': 'true', | ||||
|         '_dash.hideLinks': 'true', | ||||
|       }); | ||||
|       expect(setState).toHaveBeenCalledTimes(1); | ||||
| 
 | ||||
|       expect(setState).toHaveBeenCalledTimes(0); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  |  | |||
|  | @ -43,28 +43,31 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> { | |||
|     keys: ['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks'], | ||||
|   }); | ||||
| 
 | ||||
|   /** | ||||
|    * We want the hideXX url keys to only sync one way (url => state) on init | ||||
|    * We don't want these flags to be added to URL. | ||||
|    */ | ||||
|   getUrlState() { | ||||
|     return { | ||||
|       '_dash.hideTimePicker': this.state.hideTimeControls ? 'true' : undefined, | ||||
|       '_dash.hideVariables': this.state.hideVariableControls ? 'true' : undefined, | ||||
|       '_dash.hideLinks': this.state.hideLinksControls ? 'true' : undefined, | ||||
|     }; | ||||
|     return {}; | ||||
|   } | ||||
| 
 | ||||
|   updateFromUrl(values: SceneObjectUrlValues) { | ||||
|     const update: Partial<DashboardControlsState> = {}; | ||||
|     const { hideTimeControls, hideVariableControls, hideLinksControls } = this.state; | ||||
|     const isEnabledViaUrl = (key: string) => values[key] === 'true' || values[key] === ''; | ||||
| 
 | ||||
|     update.hideTimeControls = | ||||
|       values['_dash.hideTimePicker'] === 'true' || values['_dash.hideTimePicker'] === '' || this.state.hideTimeControls; | ||||
|     update.hideVariableControls = | ||||
|       values['_dash.hideVariables'] === 'true' || | ||||
|       values['_dash.hideVariables'] === '' || | ||||
|       this.state.hideVariableControls; | ||||
|     update.hideLinksControls = | ||||
|       values['_dash.hideLinks'] === 'true' || values['_dash.hideLinks'] === '' || this.state.hideLinksControls; | ||||
|     // Only allow hiding, never "unhiding" from url
 | ||||
|     // Becasue this should really only change on first init it's fine to do multiple setState here
 | ||||
| 
 | ||||
|     if (Object.entries(update).some(([k, v]) => v !== this.state[k as keyof DashboardControlsState])) { | ||||
|       this.setState(update); | ||||
|     if (!hideTimeControls && isEnabledViaUrl('_dash.hideTimePicker')) { | ||||
|       this.setState({ hideTimeControls: true }); | ||||
|     } | ||||
| 
 | ||||
|     if (!hideVariableControls && isEnabledViaUrl('_dash.hideVariables')) { | ||||
|       this.setState({ hideVariableControls: true }); | ||||
|     } | ||||
| 
 | ||||
|     if (!hideLinksControls && isEnabledViaUrl('_dash.hideLinks')) { | ||||
|       this.setState({ hideLinksControls: true }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,8 +2,8 @@ import { Component } from 'react'; | |||
| import { Unsubscribable } from 'rxjs'; | ||||
| 
 | ||||
| import { dateMath, TimeRange, TimeZone } from '@grafana/data'; | ||||
| import { config, TimeRangeUpdatedEvent } from '@grafana/runtime'; | ||||
| import { defaultIntervals, getWeekStart, RefreshPicker } from '@grafana/ui'; | ||||
| import { TimeRangeUpdatedEvent } from '@grafana/runtime'; | ||||
| import { defaultIntervals, RefreshPicker } from '@grafana/ui'; | ||||
| import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePickerWithHistory'; | ||||
| import { appEvents } from 'app/core/core'; | ||||
| import { t } from 'app/core/internationalization'; | ||||
|  | @ -100,7 +100,7 @@ export class DashNavTimeControls extends Component<Props> { | |||
|     const timeZone = dashboard.getTimezone(); | ||||
|     const fiscalYearStartMonth = dashboard.fiscalYearStartMonth; | ||||
|     const hideIntervalPicker = dashboard.panelInEdit?.isEditing; | ||||
|     const weekStart = dashboard.weekStart || getWeekStart(config.bootData.user.weekStart); | ||||
|     const weekStart = dashboard.weekStart; | ||||
| 
 | ||||
|     let text: string | undefined = undefined; | ||||
|     if (dashboard.refresh === AutoRefreshInterval) { | ||||
|  |  | |||
|  | @ -1,9 +1,8 @@ | |||
| import { Component } from 'react'; | ||||
| 
 | ||||
| import { TimeRange, RawTimeRange, dateTimeForTimeZone, dateMath } from '@grafana/data'; | ||||
| import { config, reportInteraction } from '@grafana/runtime'; | ||||
| import { reportInteraction } from '@grafana/runtime'; | ||||
| import { TimeZone } from '@grafana/schema'; | ||||
| import { getWeekStart } from '@grafana/ui'; | ||||
| import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePickerWithHistory'; | ||||
| import { getShiftedTimeRange, getZoomedTimeRange } from 'app/core/utils/timePicker'; | ||||
| 
 | ||||
|  | @ -86,7 +85,7 @@ export class ExploreTimeControls extends Component<Props> { | |||
|       onZoom: this.onZoom, | ||||
|       hideText, | ||||
|     }; | ||||
|     const weekStart = getWeekStart(config.bootData.user.weekStart); | ||||
| 
 | ||||
|     return ( | ||||
|       <TimePickerWithHistory | ||||
|         isOnCanvas | ||||
|  | @ -97,7 +96,6 @@ export class ExploreTimeControls extends Component<Props> { | |||
|         onChange={this.onChangeTimePicker} | ||||
|         onChangeTimeZone={onChangeTimeZone} | ||||
|         onChangeFiscalYearStartMonth={onChangeFiscalYearStartMonth} | ||||
|         weekStart={weekStart} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ export function getQueryMatches(query: string, spans: TraceSpan[] | TNil) { | |||
|   const isTextInKeyValues = (kvs: TraceKeyValuePair[]) => | ||||
|     kvs | ||||
|       ? kvs.some((kv) => { | ||||
|           return isTextInQuery(queryParts, kv.key) || isTextInQuery(queryParts, kv.value.toString()); | ||||
|           return isTextInQuery(queryParts, kv.key) || isTextInQuery(queryParts, getStringValue(kv.value)); | ||||
|         }) | ||||
|       : false; | ||||
| 
 | ||||
|  | @ -190,11 +190,15 @@ const checkKeyForMatch = (tagKey: string, key: string) => { | |||
| }; | ||||
| 
 | ||||
| const checkKeyAndValueForMatch = (tag: Tag, kv: TraceKeyValuePair) => { | ||||
|   return tag.key === kv.key.toString() && tag.value === kv.value.toString(); | ||||
|   return tag.key === kv.key && tag.value === getStringValue(kv.value); | ||||
| }; | ||||
| 
 | ||||
| const checkKeyAndValueForRegex = (tag: Tag, kv: TraceKeyValuePair) => { | ||||
|   return kv.key.toString().includes(tag.key || '') && kv.value.toString().includes(tag.value || ''); | ||||
|   return kv.key.includes(tag.key || '') && getStringValue(kv.value).includes(tag.value || ''); | ||||
| }; | ||||
| 
 | ||||
| const getStringValue = (value: string | number | boolean | undefined) => { | ||||
|   return value ? value.toString() : ''; | ||||
| }; | ||||
| 
 | ||||
| const getServiceNameMatches = (spans: TraceSpan[], searchProps: SearchProps) => { | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import { css, cx } from '@emotion/css'; | ||||
| import { css } from '@emotion/css'; | ||||
| import { useMemo } from 'react'; | ||||
| 
 | ||||
| import { AppPlugin, GrafanaTheme2, PluginContextProvider, UrlQueryMap } from '@grafana/data'; | ||||
|  | @ -45,7 +45,7 @@ export function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.E | |||
|   if (pageId === PluginTabIds.OVERVIEW) { | ||||
|     return ( | ||||
|       <div | ||||
|         className={cx(styles.readme, styles.container)} | ||||
|         className={styles.readme} | ||||
|         dangerouslySetInnerHTML={{ | ||||
|           __html: plugin.details?.readme ?? 'No plugin help or readme markdown file was found', | ||||
|         }} | ||||
|  | @ -55,7 +55,7 @@ export function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.E | |||
| 
 | ||||
|   if (pageId === PluginTabIds.VERSIONS) { | ||||
|     return ( | ||||
|       <div className={styles.container}> | ||||
|       <div> | ||||
|         <VersionList versions={plugin.details?.versions} installedVersion={plugin.installedVersion} /> | ||||
|       </div> | ||||
|     ); | ||||
|  | @ -67,7 +67,7 @@ export function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.E | |||
| 
 | ||||
|   if (pageId === PluginTabIds.CONFIG && pluginConfig?.angularConfigCtrl) { | ||||
|     return ( | ||||
|       <div className={styles.container}> | ||||
|       <div> | ||||
|         <AppConfigCtrlWrapper app={pluginConfig as AppPlugin} /> | ||||
|       </div> | ||||
|     ); | ||||
|  | @ -102,7 +102,7 @@ export function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.E | |||
|     for (const configPage of pluginConfig.configPages) { | ||||
|       if (pageId === configPage.id) { | ||||
|         return ( | ||||
|           <div className={styles.container}> | ||||
|           <div> | ||||
|             <PluginContextProvider meta={pluginConfig.meta}> | ||||
|               <configPage.body plugin={pluginConfig} query={queryParams} /> | ||||
|             </PluginContextProvider> | ||||
|  | @ -114,7 +114,7 @@ export function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.E | |||
| 
 | ||||
|   if (pageId === PluginTabIds.USAGE && pluginConfig) { | ||||
|     return ( | ||||
|       <div className={styles.container}> | ||||
|       <div> | ||||
|         <PluginUsage plugin={pluginConfig?.meta} /> | ||||
|       </div> | ||||
|     ); | ||||
|  | @ -122,25 +122,20 @@ export function PluginDetailsBody({ plugin, queryParams, pageId }: Props): JSX.E | |||
| 
 | ||||
|   if (pageId === PluginTabIds.DASHBOARDS && pluginConfig) { | ||||
|     return ( | ||||
|       <div className={styles.container}> | ||||
|       <div> | ||||
|         <PluginDashboards plugin={pluginConfig?.meta} /> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={styles.container}> | ||||
|     <div> | ||||
|       <p>Page not found.</p> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export const getStyles = (theme: GrafanaTheme2) => ({ | ||||
|   container: config.featureToggles.bodyScrolling | ||||
|     ? css({}) | ||||
|     : css({ | ||||
|         height: '100%', | ||||
|       }), | ||||
|   readme: css({ | ||||
|     '& img': { | ||||
|       maxWidth: '100%', | ||||
|  |  | |||
|  | @ -113,15 +113,9 @@ export const getStyles = (theme: GrafanaTheme2) => { | |||
|       gap: theme.spacing(1), | ||||
|     }), | ||||
|     // Needed due to block formatting context
 | ||||
|     tabContent: config.featureToggles.bodyScrolling | ||||
|       ? css({ | ||||
|           paddingLeft: '5px', | ||||
|         }) | ||||
|       : css({ | ||||
|           overflow: 'auto', | ||||
|           height: '100%', | ||||
|           paddingLeft: '5px', | ||||
|         }), | ||||
|     tabContent: css({ | ||||
|       paddingLeft: '5px', | ||||
|     }), | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,8 +31,8 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/prismjs": "1.26.4", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|  | @ -50,5 +50,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -33,8 +33,8 @@ | |||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/debounce-promise": "3.1.9", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/prismjs": "1.26.4", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|  | @ -54,5 +54,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -21,8 +21,8 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/testing-library__jest-dom": "5.14.9", | ||||
|     "ts-node": "10.9.2", | ||||
|  | @ -37,5 +37,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -26,8 +26,8 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/prismjs": "1.26.4", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|  | @ -47,5 +47,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -29,8 +29,8 @@ | |||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/d3-random": "^3.0.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "@types/testing-library__jest-dom": "5.14.9", | ||||
|  | @ -47,5 +47,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -29,9 +29,9 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/logfmt": "^1.2.3", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "@types/react-window": "1.8.8", | ||||
|  | @ -48,5 +48,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ export function createTraceFrame(data: TraceResponse): DataFrame { | |||
|       { name: 'startTime', type: FieldType.number }, | ||||
|       { name: 'duration', type: FieldType.number }, | ||||
|       { name: 'logs', type: FieldType.other }, | ||||
|       { name: 'references', type: FieldType.other, values: [] }, | ||||
|       { name: 'tags', type: FieldType.other }, | ||||
|       { name: 'warnings', type: FieldType.other }, | ||||
|       { name: 'stackTraces', type: FieldType.other }, | ||||
|  | @ -44,10 +45,12 @@ export function createTraceFrame(data: TraceResponse): DataFrame { | |||
| } | ||||
| 
 | ||||
| function toSpanRow(span: Span, processes: Record<string, TraceProcess>): TraceSpanRow { | ||||
|   const parentSpanID = span.references?.find((r) => r.refType === 'CHILD_OF')?.spanID; | ||||
| 
 | ||||
|   return { | ||||
|     spanID: span.spanID, | ||||
|     traceID: span.traceID, | ||||
|     parentSpanID: span.references?.find((r) => r.refType === 'CHILD_OF')?.spanID, | ||||
|     parentSpanID: parentSpanID, | ||||
|     operationName: span.operationName, | ||||
|     // from micro to millis
 | ||||
|     startTime: span.startTime / 1000, | ||||
|  | @ -59,6 +62,7 @@ function toSpanRow(span: Span, processes: Record<string, TraceProcess>): TraceSp | |||
|     tags: span.tags, | ||||
|     warnings: span.warnings ?? undefined, | ||||
|     stackTraces: span.stackTraces, | ||||
|     references: span.references?.filter((r) => r.spanID !== parentSpanID) ?? [], // parentSpanID is pushed to references in the transformTraceDataFrame method
 | ||||
|     serviceName: processes[span.processID].serviceName, | ||||
|     serviceTags: processes[span.processID].tags, | ||||
|   }; | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ export const testResponseDataFrameFields = toVectors([ | |||
|   { name: 'startTime', values: [1605873894680.409, 1605873894680.587] }, | ||||
|   { name: 'duration', values: [1049.141, 1.847] }, | ||||
|   { name: 'logs', values: [[], []] }, | ||||
|   { name: 'references', values: [[], []] }, | ||||
|   { | ||||
|     name: 'tags', | ||||
|     values: [ | ||||
|  |  | |||
|  | @ -21,8 +21,8 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/testing-library__jest-dom": "5.14.9", | ||||
|     "ts-node": "10.9.2", | ||||
|  | @ -37,5 +37,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -21,8 +21,8 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/testing-library__jest-dom": "5.14.9", | ||||
|     "ts-node": "10.9.2", | ||||
|  | @ -37,5 +37,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -22,8 +22,8 @@ | |||
|     "@testing-library/dom": "10.0.0", | ||||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "ts-node": "10.9.2", | ||||
|  | @ -38,5 +38,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -45,8 +45,8 @@ | |||
|     "@testing-library/react": "15.0.2", | ||||
|     "@testing-library/user-event": "14.5.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/prismjs": "1.26.4", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|  | @ -66,5 +66,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -24,8 +24,8 @@ | |||
|     "@testing-library/jest-dom": "6.4.2", | ||||
|     "@testing-library/react": "15.0.2", | ||||
|     "@types/jest": "29.5.13", | ||||
|     "@types/lodash": "4.17.7", | ||||
|     "@types/node": "20.16.5", | ||||
|     "@types/lodash": "4.17.9", | ||||
|     "@types/node": "20.16.6", | ||||
|     "@types/react": "18.3.3", | ||||
|     "@types/react-dom": "18.2.25", | ||||
|     "ts-node": "10.9.2", | ||||
|  | @ -40,5 +40,5 @@ | |||
|     "build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", | ||||
|     "dev": "webpack -w -c ./webpack.config.ts --env development" | ||||
|   }, | ||||
|   "packageManager": "yarn@4.4.1" | ||||
|   "packageManager": "yarn@4.5.0" | ||||
| } | ||||
|  |  | |||
|  | @ -112,6 +112,7 @@ | |||
|       "last-delivery-attempt": "", | ||||
|       "last-delivery-failed": "", | ||||
|       "no-delivery-attempts": "", | ||||
|       "no-integrations": "", | ||||
|       "only-firing": "", | ||||
|       "telegram": { | ||||
|         "parse-mode-warning-body": "", | ||||
|  | @ -124,6 +125,11 @@ | |||
|       "label": "" | ||||
|     }, | ||||
|     "list-view": { | ||||
|       "empty": { | ||||
|         "new-alert-rule": "", | ||||
|         "new-recording-rule": "", | ||||
|         "provisioning": "" | ||||
|       }, | ||||
|       "section": { | ||||
|         "dataSourceManaged": { | ||||
|           "title": "" | ||||
|  | @ -929,6 +935,11 @@ | |||
|     } | ||||
|   }, | ||||
|   "explore-metrics": { | ||||
|     "breakdown": { | ||||
|       "clearFilter": "", | ||||
|       "labelSelect": "", | ||||
|       "noMatchingValue": "" | ||||
|     }, | ||||
|     "viewBy": "" | ||||
|   }, | ||||
|   "export": { | ||||
|  | @ -1173,8 +1184,7 @@ | |||
|     }, | ||||
|     "search-base-dns": { | ||||
|       "description": "", | ||||
|       "label": "", | ||||
|       "placeholder": "" | ||||
|       "label": "" | ||||
|     }, | ||||
|     "subtitle": "", | ||||
|     "title": "" | ||||
|  | @ -1610,6 +1620,9 @@ | |||
|     "grafana-quaderno": { | ||||
|       "title": "Grafana Quaderno" | ||||
|     }, | ||||
|     "groupsync": { | ||||
|       "subtitle": "" | ||||
|     }, | ||||
|     "help": { | ||||
|       "title": "Hilfe" | ||||
|     }, | ||||
|  | @ -2588,11 +2601,20 @@ | |||
|   "trails": { | ||||
|     "metric-overview": { | ||||
|       "description-label": "", | ||||
|       "labels-label": "", | ||||
|       "labels": "", | ||||
|       "metric-attributes": "", | ||||
|       "no-description": "", | ||||
|       "type-label": "", | ||||
|       "unit-label": "", | ||||
|       "unknown-type": "" | ||||
|     }, | ||||
|     "metric-select": { | ||||
|       "filter-by": "", | ||||
|       "otel-switch": "" | ||||
|     }, | ||||
|     "settings": { | ||||
|       "always-keep-selected-metric-graph-in-view": "", | ||||
|       "show-previews-of-metric-graphs": "" | ||||
|     } | ||||
|   }, | ||||
|   "transformations": { | ||||
|  |  | |||
|  | @ -112,6 +112,7 @@ | |||
|       "last-delivery-attempt": "", | ||||
|       "last-delivery-failed": "", | ||||
|       "no-delivery-attempts": "", | ||||
|       "no-integrations": "", | ||||
|       "only-firing": "", | ||||
|       "telegram": { | ||||
|         "parse-mode-warning-body": "", | ||||
|  | @ -124,6 +125,11 @@ | |||
|       "label": "" | ||||
|     }, | ||||
|     "list-view": { | ||||
|       "empty": { | ||||
|         "new-alert-rule": "", | ||||
|         "new-recording-rule": "", | ||||
|         "provisioning": "" | ||||
|       }, | ||||
|       "section": { | ||||
|         "dataSourceManaged": { | ||||
|           "title": "" | ||||
|  | @ -929,6 +935,11 @@ | |||
|     } | ||||
|   }, | ||||
|   "explore-metrics": { | ||||
|     "breakdown": { | ||||
|       "clearFilter": "", | ||||
|       "labelSelect": "", | ||||
|       "noMatchingValue": "" | ||||
|     }, | ||||
|     "viewBy": "" | ||||
|   }, | ||||
|   "export": { | ||||
|  | @ -1173,8 +1184,7 @@ | |||
|     }, | ||||
|     "search-base-dns": { | ||||
|       "description": "", | ||||
|       "label": "", | ||||
|       "placeholder": "" | ||||
|       "label": "" | ||||
|     }, | ||||
|     "subtitle": "", | ||||
|     "title": "" | ||||
|  | @ -1610,6 +1620,9 @@ | |||
|     "grafana-quaderno": { | ||||
|       "title": "Grafana Quaderno" | ||||
|     }, | ||||
|     "groupsync": { | ||||
|       "subtitle": "" | ||||
|     }, | ||||
|     "help": { | ||||
|       "title": "Ayuda" | ||||
|     }, | ||||
|  | @ -2588,11 +2601,20 @@ | |||
|   "trails": { | ||||
|     "metric-overview": { | ||||
|       "description-label": "", | ||||
|       "labels-label": "", | ||||
|       "labels": "", | ||||
|       "metric-attributes": "", | ||||
|       "no-description": "", | ||||
|       "type-label": "", | ||||
|       "unit-label": "", | ||||
|       "unknown-type": "" | ||||
|     }, | ||||
|     "metric-select": { | ||||
|       "filter-by": "", | ||||
|       "otel-switch": "" | ||||
|     }, | ||||
|     "settings": { | ||||
|       "always-keep-selected-metric-graph-in-view": "", | ||||
|       "show-previews-of-metric-graphs": "" | ||||
|     } | ||||
|   }, | ||||
|   "transformations": { | ||||
|  |  | |||
|  | @ -112,6 +112,7 @@ | |||
|       "last-delivery-attempt": "", | ||||
|       "last-delivery-failed": "", | ||||
|       "no-delivery-attempts": "", | ||||
|       "no-integrations": "", | ||||
|       "only-firing": "", | ||||
|       "telegram": { | ||||
|         "parse-mode-warning-body": "", | ||||
|  | @ -124,6 +125,11 @@ | |||
|       "label": "" | ||||
|     }, | ||||
|     "list-view": { | ||||
|       "empty": { | ||||
|         "new-alert-rule": "", | ||||
|         "new-recording-rule": "", | ||||
|         "provisioning": "" | ||||
|       }, | ||||
|       "section": { | ||||
|         "dataSourceManaged": { | ||||
|           "title": "" | ||||
|  | @ -929,6 +935,11 @@ | |||
|     } | ||||
|   }, | ||||
|   "explore-metrics": { | ||||
|     "breakdown": { | ||||
|       "clearFilter": "", | ||||
|       "labelSelect": "", | ||||
|       "noMatchingValue": "" | ||||
|     }, | ||||
|     "viewBy": "" | ||||
|   }, | ||||
|   "export": { | ||||
|  | @ -1173,8 +1184,7 @@ | |||
|     }, | ||||
|     "search-base-dns": { | ||||
|       "description": "", | ||||
|       "label": "", | ||||
|       "placeholder": "" | ||||
|       "label": "" | ||||
|     }, | ||||
|     "subtitle": "", | ||||
|     "title": "" | ||||
|  | @ -1610,6 +1620,9 @@ | |||
|     "grafana-quaderno": { | ||||
|       "title": "Grafana Quaderno" | ||||
|     }, | ||||
|     "groupsync": { | ||||
|       "subtitle": "" | ||||
|     }, | ||||
|     "help": { | ||||
|       "title": "Aide" | ||||
|     }, | ||||
|  | @ -2588,11 +2601,20 @@ | |||
|   "trails": { | ||||
|     "metric-overview": { | ||||
|       "description-label": "", | ||||
|       "labels-label": "", | ||||
|       "labels": "", | ||||
|       "metric-attributes": "", | ||||
|       "no-description": "", | ||||
|       "type-label": "", | ||||
|       "unit-label": "", | ||||
|       "unknown-type": "" | ||||
|     }, | ||||
|     "metric-select": { | ||||
|       "filter-by": "", | ||||
|       "otel-switch": "" | ||||
|     }, | ||||
|     "settings": { | ||||
|       "always-keep-selected-metric-graph-in-view": "", | ||||
|       "show-previews-of-metric-graphs": "" | ||||
|     } | ||||
|   }, | ||||
|   "transformations": { | ||||
|  |  | |||
|  | @ -112,6 +112,7 @@ | |||
|       "last-delivery-attempt": "", | ||||
|       "last-delivery-failed": "", | ||||
|       "no-delivery-attempts": "", | ||||
|       "no-integrations": "", | ||||
|       "only-firing": "", | ||||
|       "telegram": { | ||||
|         "parse-mode-warning-body": "", | ||||
|  | @ -124,6 +125,11 @@ | |||
|       "label": "" | ||||
|     }, | ||||
|     "list-view": { | ||||
|       "empty": { | ||||
|         "new-alert-rule": "", | ||||
|         "new-recording-rule": "", | ||||
|         "provisioning": "" | ||||
|       }, | ||||
|       "section": { | ||||
|         "dataSourceManaged": { | ||||
|           "title": "" | ||||
|  | @ -929,6 +935,11 @@ | |||
|     } | ||||
|   }, | ||||
|   "explore-metrics": { | ||||
|     "breakdown": { | ||||
|       "clearFilter": "", | ||||
|       "labelSelect": "", | ||||
|       "noMatchingValue": "" | ||||
|     }, | ||||
|     "viewBy": "" | ||||
|   }, | ||||
|   "export": { | ||||
|  | @ -1173,8 +1184,7 @@ | |||
|     }, | ||||
|     "search-base-dns": { | ||||
|       "description": "", | ||||
|       "label": "", | ||||
|       "placeholder": "" | ||||
|       "label": "" | ||||
|     }, | ||||
|     "subtitle": "", | ||||
|     "title": "" | ||||
|  | @ -1610,6 +1620,9 @@ | |||
|     "grafana-quaderno": { | ||||
|       "title": "Grafana Quaderno" | ||||
|     }, | ||||
|     "groupsync": { | ||||
|       "subtitle": "" | ||||
|     }, | ||||
|     "help": { | ||||
|       "title": "Ajuda" | ||||
|     }, | ||||
|  | @ -2588,11 +2601,20 @@ | |||
|   "trails": { | ||||
|     "metric-overview": { | ||||
|       "description-label": "", | ||||
|       "labels-label": "", | ||||
|       "labels": "", | ||||
|       "metric-attributes": "", | ||||
|       "no-description": "", | ||||
|       "type-label": "", | ||||
|       "unit-label": "", | ||||
|       "unknown-type": "" | ||||
|     }, | ||||
|     "metric-select": { | ||||
|       "filter-by": "", | ||||
|       "otel-switch": "" | ||||
|     }, | ||||
|     "settings": { | ||||
|       "always-keep-selected-metric-graph-in-view": "", | ||||
|       "show-previews-of-metric-graphs": "" | ||||
|     } | ||||
|   }, | ||||
|   "transformations": { | ||||
|  |  | |||
|  | @ -112,6 +112,7 @@ | |||
|       "last-delivery-attempt": "", | ||||
|       "last-delivery-failed": "", | ||||
|       "no-delivery-attempts": "", | ||||
|       "no-integrations": "", | ||||
|       "only-firing": "", | ||||
|       "telegram": { | ||||
|         "parse-mode-warning-body": "", | ||||
|  | @ -123,6 +124,11 @@ | |||
|       "label": "" | ||||
|     }, | ||||
|     "list-view": { | ||||
|       "empty": { | ||||
|         "new-alert-rule": "", | ||||
|         "new-recording-rule": "", | ||||
|         "provisioning": "" | ||||
|       }, | ||||
|       "section": { | ||||
|         "dataSourceManaged": { | ||||
|           "title": "" | ||||
|  | @ -921,6 +927,11 @@ | |||
|     } | ||||
|   }, | ||||
|   "explore-metrics": { | ||||
|     "breakdown": { | ||||
|       "clearFilter": "", | ||||
|       "labelSelect": "", | ||||
|       "noMatchingValue": "" | ||||
|     }, | ||||
|     "viewBy": "" | ||||
|   }, | ||||
|   "export": { | ||||
|  | @ -1165,8 +1176,7 @@ | |||
|     }, | ||||
|     "search-base-dns": { | ||||
|       "description": "", | ||||
|       "label": "", | ||||
|       "placeholder": "" | ||||
|       "label": "" | ||||
|     }, | ||||
|     "subtitle": "", | ||||
|     "title": "" | ||||
|  | @ -1601,6 +1611,9 @@ | |||
|     "grafana-quaderno": { | ||||
|       "title": "Grafana Quaderno" | ||||
|     }, | ||||
|     "groupsync": { | ||||
|       "subtitle": "" | ||||
|     }, | ||||
|     "help": { | ||||
|       "title": "帮助" | ||||
|     }, | ||||
|  | @ -2576,11 +2589,20 @@ | |||
|   "trails": { | ||||
|     "metric-overview": { | ||||
|       "description-label": "", | ||||
|       "labels-label": "", | ||||
|       "labels": "", | ||||
|       "metric-attributes": "", | ||||
|       "no-description": "", | ||||
|       "type-label": "", | ||||
|       "unit-label": "", | ||||
|       "unknown-type": "" | ||||
|     }, | ||||
|     "metric-select": { | ||||
|       "filter-by": "", | ||||
|       "otel-switch": "" | ||||
|     }, | ||||
|     "settings": { | ||||
|       "always-keep-selected-metric-graph-in-view": "", | ||||
|       "show-previews-of-metric-graphs": "" | ||||
|     } | ||||
|   }, | ||||
|   "transformations": { | ||||
|  |  | |||
							
								
								
									
										384
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										384
									
								
								yarn.lock
								
								
								
								
							|  | @ -2963,15 +2963,15 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@floating-ui/react-dom@npm:^2.1.0, @floating-ui/react-dom@npm:^2.1.1": | ||||
|   version: 2.1.1 | ||||
|   resolution: "@floating-ui/react-dom@npm:2.1.1" | ||||
| "@floating-ui/react-dom@npm:^2.1.0, @floating-ui/react-dom@npm:^2.1.2": | ||||
|   version: 2.1.2 | ||||
|   resolution: "@floating-ui/react-dom@npm:2.1.2" | ||||
|   dependencies: | ||||
|     "@floating-ui/dom": "npm:^1.0.0" | ||||
|   peerDependencies: | ||||
|     react: ">=16.8.0" | ||||
|     react-dom: ">=16.8.0" | ||||
|   checksum: 10/cafabfb5dd0b25547863520b3bcf6faee7f087d0c3187a8779910a6838d496bf494f237bf1fe883bbfae1a7fcc399611ae52377b696065d8118bd7c1b9c0d253 | ||||
|   checksum: 10/2a67dc8499674e42ff32c7246bded185bb0fdd492150067caf9568569557ac4756a67787421d8604b0f241e5337de10762aee270d9aeef106d078a0ff13596c4 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  | @ -2989,24 +2989,24 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@floating-ui/react@npm:0.26.23": | ||||
|   version: 0.26.23 | ||||
|   resolution: "@floating-ui/react@npm:0.26.23" | ||||
| "@floating-ui/react@npm:0.26.24": | ||||
|   version: 0.26.24 | ||||
|   resolution: "@floating-ui/react@npm:0.26.24" | ||||
|   dependencies: | ||||
|     "@floating-ui/react-dom": "npm:^2.1.1" | ||||
|     "@floating-ui/utils": "npm:^0.2.7" | ||||
|     "@floating-ui/react-dom": "npm:^2.1.2" | ||||
|     "@floating-ui/utils": "npm:^0.2.8" | ||||
|     tabbable: "npm:^6.0.0" | ||||
|   peerDependencies: | ||||
|     react: ">=16.8.0" | ||||
|     react-dom: ">=16.8.0" | ||||
|   checksum: 10/a2ffeb0bae72cac9e6583d9651e75e94c261a9e78ca4a5e862b7d33f2c19ae014cbe272627a0a0a5a2b526280efab17ec687d32ba02f6ce4e924bec562ae06ab | ||||
|   checksum: 10/903ffbee2c6726d117086e2a83f43d6ad339970758ce7979fd16cc7cf8dc0f5b869bd72c2c8ee1bcd6c63b190bb0960effd4d403e63685fb5aeed6b185041b08 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@floating-ui/utils@npm:^0.2.0, @floating-ui/utils@npm:^0.2.7": | ||||
|   version: 0.2.7 | ||||
|   resolution: "@floating-ui/utils@npm:0.2.7" | ||||
|   checksum: 10/56b1bb3f73f6ec9aabf9b1fd3dc584e0f2384d319c1a6119050eab102ae6ca8b9b0eed711c2f235ffe035188cbe9727bf36e8dcb54c8bd32176737e4be47efa8 | ||||
| "@floating-ui/utils@npm:^0.2.0, @floating-ui/utils@npm:^0.2.8": | ||||
|   version: 0.2.8 | ||||
|   resolution: "@floating-ui/utils@npm:0.2.8" | ||||
|   checksum: 10/3e3ea3b2de06badc4baebdf358b3dbd77ccd9474a257a6ef237277895943db2acbae756477ec64de65a2a1436d94aea3107129a1feeef6370675bf2b161c1abc | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  | @ -3130,8 +3130,8 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/prismjs": "npm:1.26.4" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|  | @ -3172,8 +3172,8 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/testing-library__jest-dom": "npm:5.14.9" | ||||
|     lodash: "npm:4.17.21" | ||||
|  | @ -3203,8 +3203,8 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/prismjs": "npm:1.26.4" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|  | @ -3246,8 +3246,8 @@ __metadata: | |||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/d3-random": "npm:^3.0.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     "@types/testing-library__jest-dom": "npm:5.14.9" | ||||
|  | @ -3287,9 +3287,9 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/logfmt": "npm:^1.2.3" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     "@types/react-window": "npm:1.8.8" | ||||
|  | @ -3327,8 +3327,8 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/testing-library__jest-dom": "npm:5.14.9" | ||||
|     lodash: "npm:4.17.21" | ||||
|  | @ -3358,8 +3358,8 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/testing-library__jest-dom": "npm:5.14.9" | ||||
|     lodash: "npm:4.17.21" | ||||
|  | @ -3387,8 +3387,8 @@ __metadata: | |||
|     "@testing-library/dom": "npm:10.0.0" | ||||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     lodash: "npm:4.17.21" | ||||
|  | @ -3424,8 +3424,8 @@ __metadata: | |||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/debounce-promise": "npm:3.1.9" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/prismjs": "npm:1.26.4" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|  | @ -3480,8 +3480,8 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/prismjs": "npm:1.26.4" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|  | @ -3529,8 +3529,8 @@ __metadata: | |||
|     "@testing-library/jest-dom": "npm:6.4.2" | ||||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     lodash: "npm:4.17.21" | ||||
|  | @ -3587,8 +3587,8 @@ __metadata: | |||
|     "@types/d3-interpolate": "npm:^3.0.0" | ||||
|     "@types/dompurify": "npm:^3.0.0" | ||||
|     "@types/history": "npm:4.7.11" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/papaparse": "npm:5.3.14" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|  | @ -3635,7 +3635,7 @@ __metadata: | |||
|   dependencies: | ||||
|     "@grafana/tsconfig": "npm:^2.0.0" | ||||
|     "@rollup/plugin-node-resolve": "npm:15.2.4" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     esbuild: "npm:0.24.0" | ||||
|     rimraf: "npm:6.0.1" | ||||
|     rollup: "npm:2.79.1" | ||||
|  | @ -3753,7 +3753,7 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@grafana/faro-web-sdk@npm:1.10.0, @grafana/faro-web-sdk@npm:^1.3.6, @grafana/faro-web-sdk@npm:^1.9.1": | ||||
| "@grafana/faro-web-sdk@npm:1.10.0, @grafana/faro-web-sdk@npm:^1.10.0, @grafana/faro-web-sdk@npm:^1.3.6": | ||||
|   version: 1.10.0 | ||||
|   resolution: "@grafana/faro-web-sdk@npm:1.10.0" | ||||
|   dependencies: | ||||
|  | @ -3765,22 +3765,22 @@ __metadata: | |||
|   linkType: hard | ||||
| 
 | ||||
| "@grafana/faro-web-tracing@npm:^1.8.2": | ||||
|   version: 1.9.1 | ||||
|   resolution: "@grafana/faro-web-tracing@npm:1.9.1" | ||||
|   version: 1.10.0 | ||||
|   resolution: "@grafana/faro-web-tracing@npm:1.10.0" | ||||
|   dependencies: | ||||
|     "@grafana/faro-web-sdk": "npm:^1.9.1" | ||||
|     "@grafana/faro-web-sdk": "npm:^1.10.0" | ||||
|     "@opentelemetry/api": "npm:^1.9.0" | ||||
|     "@opentelemetry/context-zone": "npm:1.21.0" | ||||
|     "@opentelemetry/core": "npm:^1.25.0" | ||||
|     "@opentelemetry/exporter-trace-otlp-http": "npm:^0.52.0" | ||||
|     "@opentelemetry/instrumentation": "npm:^0.52.0" | ||||
|     "@opentelemetry/instrumentation-fetch": "npm:^0.52.0" | ||||
|     "@opentelemetry/instrumentation-xml-http-request": "npm:^0.52.0" | ||||
|     "@opentelemetry/otlp-transformer": "npm:^0.52.0" | ||||
|     "@opentelemetry/resources": "npm:^1.25.0" | ||||
|     "@opentelemetry/sdk-trace-web": "npm:^1.25.0" | ||||
|     "@opentelemetry/semantic-conventions": "npm:^1.25.0" | ||||
|   checksum: 10/cd62af5b0cb177b33b80eb99c2c1c995485497bd383124dd4dcd45c2de8cfd2e081cff42b95fe326872cfaa433d460273de5b4a1dfe6f1147620591b337b46e9 | ||||
|     "@opentelemetry/context-zone": "npm:1.26.0" | ||||
|     "@opentelemetry/core": "npm:^1.26.0" | ||||
|     "@opentelemetry/exporter-trace-otlp-http": "npm:^0.53.0" | ||||
|     "@opentelemetry/instrumentation": "npm:^0.53.0" | ||||
|     "@opentelemetry/instrumentation-fetch": "npm:^0.53.0" | ||||
|     "@opentelemetry/instrumentation-xml-http-request": "npm:^0.53.0" | ||||
|     "@opentelemetry/otlp-transformer": "npm:^0.53.0" | ||||
|     "@opentelemetry/resources": "npm:^1.26.0" | ||||
|     "@opentelemetry/sdk-trace-web": "npm:^1.26.0" | ||||
|     "@opentelemetry/semantic-conventions": "npm:^1.27.0" | ||||
|   checksum: 10/ba986abf1e91b0b829f101e0f7abbd7cb14ff76c7968c30051d1005c2ab1f13e41118441e1d8fe76c3a71890e47ff24e9af185464d1e86ef6616af5c3fa7f4d1 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  | @ -3803,8 +3803,8 @@ __metadata: | |||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/d3": "npm:^7" | ||||
|     "@types/jest": "npm:^29.5.4" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-virtualized-auto-sizer": "npm:1.0.4" | ||||
|     "@types/tinycolor2": "npm:1.4.6" | ||||
|  | @ -3888,7 +3888,7 @@ __metadata: | |||
|     "@testing-library/react": "npm:15.0.2" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:^29.5.4" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/systemjs": "npm:6.15.1" | ||||
|     "@types/testing-library__jest-dom": "npm:5.14.9" | ||||
|  | @ -3946,7 +3946,7 @@ __metadata: | |||
|   dependencies: | ||||
|     "@emotion/css": "npm:11.11.2" | ||||
|     "@emotion/eslint-plugin": "npm:11.11.0" | ||||
|     "@floating-ui/react": "npm:0.26.23" | ||||
|     "@floating-ui/react": "npm:0.26.24" | ||||
|     "@grafana/data": "npm:11.3.0-pre" | ||||
|     "@grafana/e2e-selectors": "npm:11.3.0-pre" | ||||
|     "@grafana/experimental": "npm:1.8.0" | ||||
|  | @ -3975,8 +3975,8 @@ __metadata: | |||
|     "@types/eslint": "npm:8.56.10" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/jquery": "npm:3.5.30" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/pluralize": "npm:^0.0.33" | ||||
|     "@types/prismjs": "npm:1.26.4" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|  | @ -4069,7 +4069,7 @@ __metadata: | |||
|     "@types/angular": "npm:1.8.9" | ||||
|     "@types/history": "npm:4.7.11" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     "@types/systemjs": "npm:6.15.1" | ||||
|  | @ -4108,7 +4108,7 @@ __metadata: | |||
|     "@svgr/plugin-prettier": "npm:^8.1.0" | ||||
|     "@svgr/plugin-svgo": "npm:^8.1.0" | ||||
|     "@types/babel__core": "npm:^7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     esbuild: "npm:0.24.0" | ||||
|  | @ -4187,8 +4187,8 @@ __metadata: | |||
|     "@testing-library/react-hooks": "npm:^8.0.1" | ||||
|     "@testing-library/user-event": "npm:14.5.2" | ||||
|     "@types/jest": "npm:^29.5.4" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-dom": "npm:18.2.25" | ||||
|     "@types/react-virtualized-auto-sizer": "npm:1.0.4" | ||||
|  | @ -4237,7 +4237,7 @@ __metadata: | |||
|     "@emotion/css": "npm:11.11.2" | ||||
|     "@emotion/react": "npm:11.11.4" | ||||
|     "@faker-js/faker": "npm:^8.4.1" | ||||
|     "@floating-ui/react": "npm:0.26.23" | ||||
|     "@floating-ui/react": "npm:0.26.24" | ||||
|     "@grafana/data": "npm:11.3.0-pre" | ||||
|     "@grafana/e2e-selectors": "npm:11.3.0-pre" | ||||
|     "@grafana/faro-web-sdk": "npm:^1.3.6" | ||||
|  | @ -4280,9 +4280,9 @@ __metadata: | |||
|     "@types/is-hotkey": "npm:0.1.10" | ||||
|     "@types/jest": "npm:29.5.13" | ||||
|     "@types/jquery": "npm:3.5.30" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/mock-raf": "npm:1.0.6" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/prismjs": "npm:1.26.4" | ||||
|     "@types/react": "npm:18.3.3" | ||||
|     "@types/react-color": "npm:3.0.12" | ||||
|  | @ -5842,15 +5842,6 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/api-logs@npm:0.52.1": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/api-logs@npm:0.52.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/api": "npm:^1.0.0" | ||||
|   checksum: 10/7515667a41a38014ffda70674c0b77c9c68417cde9f8ce8840e675308b4431f99d879e8d347f1b08486561617f914c07ee704ad6ed8a6522dabc3a81ac39dc88 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/api-logs@npm:0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/api-logs@npm:0.53.0" | ||||
|  | @ -5876,23 +5867,23 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/context-zone-peer-dep@npm:1.21.0": | ||||
|   version: 1.21.0 | ||||
|   resolution: "@opentelemetry/context-zone-peer-dep@npm:1.21.0" | ||||
| "@opentelemetry/context-zone-peer-dep@npm:1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/context-zone-peer-dep@npm:1.26.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.0.0 <1.8.0" | ||||
|     zone.js: ^0.10.2 || ^0.11.0 || ^0.13.0 | ||||
|   checksum: 10/e89bfb8b5dd35ef86fd67f6bab9abd0d5c17027611b3d75f01419d9267a7ee8a1976af9198feabf8ea5f199badee7c0c5b34b2b3f3820fd5409aedc28c1abfc0 | ||||
|     "@opentelemetry/api": ">=1.0.0 <1.10.0" | ||||
|     zone.js: ^0.10.2 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0 | ||||
|   checksum: 10/aed06016c380001418656810f80d24b68d05ce8d8138ed278fd27ed7990961b02dc4f3e1e75511662eb97afcfb4b7f96be2dfd28894eba3edff375be8908749a | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/context-zone@npm:1.21.0": | ||||
|   version: 1.21.0 | ||||
|   resolution: "@opentelemetry/context-zone@npm:1.21.0" | ||||
| "@opentelemetry/context-zone@npm:1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/context-zone@npm:1.26.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/context-zone-peer-dep": "npm:1.21.0" | ||||
|     zone.js: "npm:^0.11.0" | ||||
|   checksum: 10/7b925ad7a4d9087b1d5ea39042cb8a9e30c7b21c675e9e470531e80579c891e80faec822bd70384a44f49a73284145150c0f01a205ff7958ce1eb2ae8fc93881 | ||||
|     "@opentelemetry/context-zone-peer-dep": "npm:1.26.0" | ||||
|     zone.js: "npm:^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0" | ||||
|   checksum: 10/16ddaa1129e818a6950db15f5f2c254e7d3216f2e7deb93ecb5b11496d4a68ea043cc469ac0f426840b797a21ad9162daabe74b5311ac3d0661fc6b64c51fff6 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  | @ -5908,18 +5899,7 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/core@npm:1.25.1": | ||||
|   version: 1.25.1 | ||||
|   resolution: "@opentelemetry/core@npm:1.25.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.25.1" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.0.0 <1.10.0" | ||||
|   checksum: 10/3f669798760e70587cb1f329def5c02b586d3ceeb3200728387e6fb6dcd5ac9a04e4eafe3dc98a6c0cf5204e4ca238d4f0809a37425a1f1e7e9aea673ea28f59 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/core@npm:1.26.0, @opentelemetry/core@npm:^1.25.0": | ||||
| "@opentelemetry/core@npm:1.26.0, @opentelemetry/core@npm:^1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/core@npm:1.26.0" | ||||
|   dependencies: | ||||
|  | @ -5945,95 +5925,78 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/exporter-trace-otlp-http@npm:^0.52.0": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/exporter-trace-otlp-http@npm:0.52.1" | ||||
| "@opentelemetry/exporter-trace-otlp-http@npm:^0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/exporter-trace-otlp-http@npm:0.53.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/otlp-exporter-base": "npm:0.52.1" | ||||
|     "@opentelemetry/otlp-transformer": "npm:0.52.1" | ||||
|     "@opentelemetry/resources": "npm:1.25.1" | ||||
|     "@opentelemetry/sdk-trace-base": "npm:1.25.1" | ||||
|     "@opentelemetry/core": "npm:1.26.0" | ||||
|     "@opentelemetry/otlp-exporter-base": "npm:0.53.0" | ||||
|     "@opentelemetry/otlp-transformer": "npm:0.53.0" | ||||
|     "@opentelemetry/resources": "npm:1.26.0" | ||||
|     "@opentelemetry/sdk-trace-base": "npm:1.26.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ^1.0.0 | ||||
|   checksum: 10/12580244204ac156c0a5d059e275a8d9f1fd5b705d425b6e1c6b3045740d157f5d55190e88c430a528cdc5fa92ad8f3ae4fb157e253f9026462728b189d6b6c3 | ||||
|   checksum: 10/28c75e25564833bc448b5733415730483c9f28714577acb679087d5ccfc46d74b3f24996c41f2c93bf6a6406edb1cad7e8cf2a76b61096e3f417f90044e1d795 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/instrumentation-fetch@npm:^0.52.0": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/instrumentation-fetch@npm:0.52.1" | ||||
| "@opentelemetry/instrumentation-fetch@npm:^0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/instrumentation-fetch@npm:0.53.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/instrumentation": "npm:0.52.1" | ||||
|     "@opentelemetry/sdk-trace-web": "npm:1.25.1" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.25.1" | ||||
|     "@opentelemetry/core": "npm:1.26.0" | ||||
|     "@opentelemetry/instrumentation": "npm:0.53.0" | ||||
|     "@opentelemetry/sdk-trace-web": "npm:1.26.0" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.27.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ^1.0.0 | ||||
|   checksum: 10/0d21aa1c3170d77fe6e09f540304ba22d728a9ce0160e81934ab26c47545289aaca81c2f2dd435d5564c11d9a835e86641ff4bcdf6fd6185b6bd5a3edc0e04fa | ||||
|   checksum: 10/422e9c749523a2be4cd6b82304f20b3208ced12a14990b1cfee273c7485252c94618336c94342a0b0ad72863ec5519d3b1c31f0d09395c29926ecbc0986c9b15 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/instrumentation-xml-http-request@npm:^0.52.0": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/instrumentation-xml-http-request@npm:0.52.1" | ||||
| "@opentelemetry/instrumentation-xml-http-request@npm:^0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/instrumentation-xml-http-request@npm:0.53.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/instrumentation": "npm:0.52.1" | ||||
|     "@opentelemetry/sdk-trace-web": "npm:1.25.1" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.25.1" | ||||
|     "@opentelemetry/core": "npm:1.26.0" | ||||
|     "@opentelemetry/instrumentation": "npm:0.53.0" | ||||
|     "@opentelemetry/sdk-trace-web": "npm:1.26.0" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.27.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ^1.0.0 | ||||
|   checksum: 10/02833d5d940a455979df7e02f425e4eae12f8f45e00ab59c85830be58e4e0a28294391f2cb1bc0b0fe29dc68df2f0945794e6d20b4ecf6409f6a24569b6080d7 | ||||
|   checksum: 10/82c7e3d9f54fafccfabfe02033b11ca39b052134ec6e8902ac3c54993745fc02503f60e7d223b74319e855091c5f961e78483857a690633958fb61852c041749 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/instrumentation@npm:0.52.1, @opentelemetry/instrumentation@npm:^0.52.0": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/instrumentation@npm:0.52.1" | ||||
| "@opentelemetry/instrumentation@npm:0.53.0, @opentelemetry/instrumentation@npm:^0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/instrumentation@npm:0.53.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/api-logs": "npm:0.52.1" | ||||
|     "@types/shimmer": "npm:^1.0.2" | ||||
|     "@opentelemetry/api-logs": "npm:0.53.0" | ||||
|     "@types/shimmer": "npm:^1.2.0" | ||||
|     import-in-the-middle: "npm:^1.8.1" | ||||
|     require-in-the-middle: "npm:^7.1.1" | ||||
|     semver: "npm:^7.5.2" | ||||
|     shimmer: "npm:^1.2.1" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ^1.3.0 | ||||
|   checksum: 10/87761bd593f2b905d88d0531a3a2a7f4b0186334ae413b4c172a86bd4de0fd6d2f906a1bfd9dd7bd172a228a44fa7a680f5802a1570dfe2fadad0768e80bd7a8 | ||||
|   checksum: 10/4b994c8568a503a15655cba249b1dbdef3f67dfda37938abba6267ba75b6d72a9aa276be4b0c8874e86f98ab89d92877e1874e0565a7e67f062c43dfcbbb16a5 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/otlp-exporter-base@npm:0.52.1": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/otlp-exporter-base@npm:0.52.1" | ||||
| "@opentelemetry/otlp-exporter-base@npm:0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/otlp-exporter-base@npm:0.53.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/otlp-transformer": "npm:0.52.1" | ||||
|     "@opentelemetry/core": "npm:1.26.0" | ||||
|     "@opentelemetry/otlp-transformer": "npm:0.53.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ^1.0.0 | ||||
|   checksum: 10/0fbe164e04b05a7ba230f5532ecfbf1bb2156e2a7330090e1880c5b1db05f89ed4e7a89a67b8297415389975045377efbfb82410685b666581eaa6782c353450 | ||||
|   checksum: 10/ca59d73ae8f83946062b060a9a382fc7db6154c892ed56b6ab7f545530ba4850b4d0a748daaa30d1177ef6a8c2a0fddd34a199080f4474ec445944cece86f1ef | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/otlp-transformer@npm:0.52.1, @opentelemetry/otlp-transformer@npm:^0.52.0": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/otlp-transformer@npm:0.52.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/api-logs": "npm:0.52.1" | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/resources": "npm:1.25.1" | ||||
|     "@opentelemetry/sdk-logs": "npm:0.52.1" | ||||
|     "@opentelemetry/sdk-metrics": "npm:1.25.1" | ||||
|     "@opentelemetry/sdk-trace-base": "npm:1.25.1" | ||||
|     protobufjs: "npm:^7.3.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.3.0 <1.10.0" | ||||
|   checksum: 10/954bef8f732bb0f4791755de73627cd6d83bde2e42337d5961d6694d90e404f20a48e941f17229ce87ef39b3bb9ddc11cc1293ac77a3e0bb2b2cca4ea660a778 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/otlp-transformer@npm:^0.53.0": | ||||
| "@opentelemetry/otlp-transformer@npm:0.53.0, @opentelemetry/otlp-transformer@npm:^0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/otlp-transformer@npm:0.53.0" | ||||
|   dependencies: | ||||
|  | @ -6062,19 +6025,7 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/resources@npm:1.25.1": | ||||
|   version: 1.25.1 | ||||
|   resolution: "@opentelemetry/resources@npm:1.25.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.25.1" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.0.0 <1.10.0" | ||||
|   checksum: 10/971f9616deeff76e584ba7d2957db402332701d9e1f679532e105ff2b929cd93e8ee40ccac029585e70ab917ff47696a0f37a4ddfcb9f96b4ae0eeca860deaf5 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/resources@npm:1.26.0, @opentelemetry/resources@npm:^1.25.0": | ||||
| "@opentelemetry/resources@npm:1.26.0, @opentelemetry/resources@npm:^1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/resources@npm:1.26.0" | ||||
|   dependencies: | ||||
|  | @ -6086,19 +6037,6 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-logs@npm:0.52.1": | ||||
|   version: 0.52.1 | ||||
|   resolution: "@opentelemetry/sdk-logs@npm:0.52.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/api-logs": "npm:0.52.1" | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/resources": "npm:1.25.1" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.4.0 <1.10.0" | ||||
|   checksum: 10/17057d6105fb2bfba7cc7860a0d01c22e2a488d90d6d065ba6938a4c5315b025fb2ed98b7d82e2e828af8ec0c046934646c651f5bf0d587d64dc23643507c4fd | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-logs@npm:0.53.0": | ||||
|   version: 0.53.0 | ||||
|   resolution: "@opentelemetry/sdk-logs@npm:0.53.0" | ||||
|  | @ -6126,19 +6064,6 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-metrics@npm:1.25.1": | ||||
|   version: 1.25.1 | ||||
|   resolution: "@opentelemetry/sdk-metrics@npm:1.25.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/resources": "npm:1.25.1" | ||||
|     lodash.merge: "npm:^4.6.2" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.3.0 <1.10.0" | ||||
|   checksum: 10/751015cef39cb13502fd03d32d46280697b24b6ceee27bf3b1336bef16259baf3fb629734cec6bf4998a14d785da467ae93cafc7b519c83cec52312269a773b3 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-metrics@npm:1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/sdk-metrics@npm:1.26.0" | ||||
|  | @ -6165,19 +6090,6 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-trace-base@npm:1.25.1": | ||||
|   version: 1.25.1 | ||||
|   resolution: "@opentelemetry/sdk-trace-base@npm:1.25.1" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/resources": "npm:1.25.1" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.25.1" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.0.0 <1.10.0" | ||||
|   checksum: 10/65d289a144bba052d1b4a0f8f528d2598cfb6bfbf60d9372543a317665e9e1dc63069a66601537fe1e6e94563f53d1be9cc3474dfc3361a8d33f31e1ea2d6262 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-trace-base@npm:1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/sdk-trace-base@npm:1.26.0" | ||||
|  | @ -6191,16 +6103,16 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/sdk-trace-web@npm:1.25.1, @opentelemetry/sdk-trace-web@npm:^1.25.0": | ||||
|   version: 1.25.1 | ||||
|   resolution: "@opentelemetry/sdk-trace-web@npm:1.25.1" | ||||
| "@opentelemetry/sdk-trace-web@npm:1.26.0, @opentelemetry/sdk-trace-web@npm:^1.26.0": | ||||
|   version: 1.26.0 | ||||
|   resolution: "@opentelemetry/sdk-trace-web@npm:1.26.0" | ||||
|   dependencies: | ||||
|     "@opentelemetry/core": "npm:1.25.1" | ||||
|     "@opentelemetry/sdk-trace-base": "npm:1.25.1" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.25.1" | ||||
|     "@opentelemetry/core": "npm:1.26.0" | ||||
|     "@opentelemetry/sdk-trace-base": "npm:1.26.0" | ||||
|     "@opentelemetry/semantic-conventions": "npm:1.27.0" | ||||
|   peerDependencies: | ||||
|     "@opentelemetry/api": ">=1.0.0 <1.10.0" | ||||
|   checksum: 10/0c12cac81b612b361704d20264c663fafb1ccfb43f3ab08c1c8ddccbdc009c02de4dd8f89129799344a6095767a3949e86bf38e4c4222992a432c2c352f77ba0 | ||||
|   checksum: 10/2882863d02510151460850575269129c603f2b3e44f5b2c34bede4128d7f724b7bb8bb8253469848110725e2b2af9340d13a81d565ea9e0c80cf57804b02d65f | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  | @ -6211,14 +6123,7 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/semantic-conventions@npm:1.25.1": | ||||
|   version: 1.25.1 | ||||
|   resolution: "@opentelemetry/semantic-conventions@npm:1.25.1" | ||||
|   checksum: 10/d84745a9e21a451560a293b4e6f996ee7c67bb983a7ec05408c23d207c6fc8b73a0af9c1ebea26e3acb4f0e3405ea7eb0d6bdf9adad9f954d60829bbb48ea307 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@opentelemetry/semantic-conventions@npm:1.27.0, @opentelemetry/semantic-conventions@npm:^1.25.0": | ||||
| "@opentelemetry/semantic-conventions@npm:1.27.0, @opentelemetry/semantic-conventions@npm:^1.27.0": | ||||
|   version: 1.27.0 | ||||
|   resolution: "@opentelemetry/semantic-conventions@npm:1.27.0" | ||||
|   checksum: 10/98166522f299e2fe3d43376adbdeb92679b75ebb172e2a3c4c71f2942bd91585e9537618efbbae6dc08177699e5719368edf66d7e69e8636f360b85217bbdbe1 | ||||
|  | @ -10168,7 +10073,14 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@types/lodash@npm:*, @types/lodash@npm:4.17.7, @types/lodash@npm:^4.14.167, @types/lodash@npm:^4.14.172": | ||||
| "@types/lodash@npm:*, @types/lodash@npm:4.17.9, @types/lodash@npm:^4.14.167, @types/lodash@npm:^4.14.172": | ||||
|   version: 4.17.9 | ||||
|   resolution: "@types/lodash@npm:4.17.9" | ||||
|   checksum: 10/49e35caaf668686be0bad9e9bef88456903a21999d3fd8bf91c302e0d5328398fb59fee793d0afbaf6edeca1b46c3e8109899d85ff3a433075178f1ab693e597 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@types/lodash@npm:4.17.7": | ||||
|   version: 4.17.7 | ||||
|   resolution: "@types/lodash@npm:4.17.7" | ||||
|   checksum: 10/b8177f19cf962414a66989837481b13f546afc2e98e8d465bec59e6ac03a59c584eb7053ce511cde3a09c5f3096d22a5ae22cfb56b23f3b0da75b0743b6b1a44 | ||||
|  | @ -10277,12 +10189,12 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@types/node@npm:*, @types/node@npm:20.16.5, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.16": | ||||
|   version: 20.16.5 | ||||
|   resolution: "@types/node@npm:20.16.5" | ||||
| "@types/node@npm:*, @types/node@npm:20.16.6, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.16": | ||||
|   version: 20.16.6 | ||||
|   resolution: "@types/node@npm:20.16.6" | ||||
|   dependencies: | ||||
|     undici-types: "npm:~6.19.2" | ||||
|   checksum: 10/39a8457149dc17cdea57afc90d4da53182fdb8b958d5bb065a15d123d81d4efa6b51a0de92428d05ead2e63ce07195586f71083401b99cdbcd04662344fbf7a1 | ||||
|   checksum: 10/f8a07b113901fa2b5bfbea8dedd15321126238023586f047576805cb1a53abd7f717f9e490d8e71d4c7b627885659f862584fa844fa71aab9c86295d1f006771 | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  | @ -10620,7 +10532,7 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "@types/shimmer@npm:^1.0.2": | ||||
| "@types/shimmer@npm:^1.2.0": | ||||
|   version: 1.2.0 | ||||
|   resolution: "@types/shimmer@npm:1.2.0" | ||||
|   checksum: 10/f081a31d826ce7bfe8cc7ba8129d2b1dffae44fd580eba4fcf741237646c4c2494ae6de2cada4b7713d138f35f4bc512dbf01311d813dee82020f97d7d8c491c | ||||
|  | @ -18890,7 +18802,7 @@ __metadata: | |||
|     "@emotion/eslint-plugin": "npm:11.11.0" | ||||
|     "@emotion/react": "npm:11.11.4" | ||||
|     "@fingerprintjs/fingerprintjs": "npm:^3.4.2" | ||||
|     "@floating-ui/react": "npm:0.26.23" | ||||
|     "@floating-ui/react": "npm:0.26.24" | ||||
|     "@formatjs/intl-durationformat": "npm:^0.2.4" | ||||
|     "@glideapps/glide-data-grid": "npm:^6.0.0" | ||||
|     "@grafana/aws-sdk": "npm:0.4.2" | ||||
|  | @ -18977,10 +18889,10 @@ __metadata: | |||
|     "@types/jquery": "npm:3.5.30" | ||||
|     "@types/js-yaml": "npm:^4.0.5" | ||||
|     "@types/jsurl": "npm:^1.2.28" | ||||
|     "@types/lodash": "npm:4.17.7" | ||||
|     "@types/lodash": "npm:4.17.9" | ||||
|     "@types/logfmt": "npm:^1.2.3" | ||||
|     "@types/lucene": "npm:^2" | ||||
|     "@types/node": "npm:20.16.5" | ||||
|     "@types/node": "npm:20.16.6" | ||||
|     "@types/node-forge": "npm:^1" | ||||
|     "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@3.2.4" | ||||
|     "@types/pluralize": "npm:^0.0.33" | ||||
|  | @ -33596,12 +33508,10 @@ __metadata: | |||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
| "zone.js@npm:^0.11.0": | ||||
|   version: 0.11.8 | ||||
|   resolution: "zone.js@npm:0.11.8" | ||||
|   dependencies: | ||||
|     tslib: "npm:^2.3.0" | ||||
|   checksum: 10/643c71eb9dc9a09510ab0d5c27ee4402f21d09b1aad1d5e1e0b7e1b98e621686e3d82a59d2646a91d655e5d2d4471e43068494dfef4aac16170b67ef46212446 | ||||
| "zone.js@npm:^0.11.0 || ^0.12.0 || ^0.13.0 || ^0.14.0": | ||||
|   version: 0.14.10 | ||||
|   resolution: "zone.js@npm:0.14.10" | ||||
|   checksum: 10/a7bed2f9a7ce67ba4e70b03b7e59dc955e4d2d738570950c4a0e16fafb5c23c47d0c6ece84f6e871a0f77d81c26a051da566d09738ebfdab297f54b862ae0b5d | ||||
|   languageName: node | ||||
|   linkType: hard | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue