Merge branch 'main' into drclau/unistor/replace-authenticators-3

This commit is contained in:
Claudiu Dragalina-Paraipan 2024-09-24 17:35:03 +03:00
commit a6c977ba4d
93 changed files with 984 additions and 1149 deletions

View File

@ -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

View File

@ -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:

View File

@ -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",

View File

@ -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,
});

View File

@ -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,
});

View File

@ -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')

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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;

View File

@ -199,7 +199,6 @@ export interface FeatureToggles {
alertingApiServer?: boolean;
dashboardRestoreUI?: boolean;
cloudWatchRoundUpEndTime?: boolean;
bodyScrolling?: boolean;
cloudwatchMetricInsightsCrossAccount?: boolean;
prometheusAzureOverrideAudience?: boolean;
alertingFilterV2?: boolean;

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -20,5 +20,5 @@
"typescript": "5.5.4",
"webpack": "5.94.0"
},
"packageManager": "yarn@4.4.1"
"packageManager": "yarn@4.5.0"
}

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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,
});
},
})}

View File

@ -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]}
/>
);
}

View File

@ -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;

View File

@ -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,
}),
};
};

View File

@ -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),

View File

@ -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',

View File

@ -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

View File

@ -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=

View File

@ -166,7 +166,7 @@ func AddKnownTypes(scheme *runtime.Scheme, version string) {
&ServiceAccountTokenList{},
&Team{},
&TeamList{},
&IdentityDisplayResults{},
&DisplayList{},
&SSOSetting{},
&SSOSettingList{},
&TeamBinding{},

View File

@ -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.

View File

@ -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"`

View File

@ -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
}

View File

@ -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"},
}
}

View File

@ -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

View File

@ -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...)
}

View File

@ -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)
}

View File

@ -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),

View File

@ -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
}

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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 {

View File

@ -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)
)

View File

@ -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",

View File

@ -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

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
180 alertingApiServer experimental @grafana/alerting-squad false true false
181 dashboardRestoreUI experimental @grafana/grafana-frontend-platform false false false
182 cloudWatchRoundUpEndTime GA @grafana/aws-datasources false false false
bodyScrolling preview @grafana/grafana-frontend-platform false false true
183 cloudwatchMetricInsightsCrossAccount preview @grafana/aws-datasources false false true
184 prometheusAzureOverrideAudience deprecated @grafana/partner-datasources false false false
185 alertingFilterV2 experimental @grafana/alerting-squad false false false

View File

@ -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"

View File

@ -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"
}

View File

@ -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 {

View File

@ -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)

View File

@ -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",

View File

@ -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,

View File

@ -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,

View File

@ -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',
}),
};
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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',

View File

@ -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);
}
}

View File

@ -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

View File

@ -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}>

View File

@ -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)}>

View File

@ -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)) {

View File

@ -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);
});
});
});

View File

@ -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 });
}
}

View File

@ -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) {

View File

@ -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}
/>
);
}

View File

@ -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) => {

View File

@ -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%',

View File

@ -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',
}),
};
};

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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,
};

View File

@ -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: [

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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": {

View File

@ -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": {

View File

@ -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": {

View File

@ -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": {

View File

@ -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
View File

@ -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