mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-03 08:33:26 +00:00
chore: variable store set up (#10145)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* chore: update CODEOWNERS file for dashboards * chore: variable store set up
This commit is contained in:
@@ -105,6 +105,7 @@
|
||||
"i18next": "^21.6.12",
|
||||
"i18next-browser-languagedetector": "^6.1.3",
|
||||
"i18next-http-backend": "^1.3.2",
|
||||
"immer": "11.1.3",
|
||||
"jest": "^27.5.1",
|
||||
"js-base64": "^3.7.2",
|
||||
"less": "^4.1.2",
|
||||
|
||||
19
frontend/src/hooks/dashboard/useDashboardVariables.ts
Normal file
19
frontend/src/hooks/dashboard/useDashboardVariables.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useSyncExternalStore } from 'react';
|
||||
|
||||
import {
|
||||
dashboardVariablesStore,
|
||||
IDashboardVariables,
|
||||
} from '../../providers/Dashboard/store/dashboardVariablesStore';
|
||||
|
||||
export const useDashboardVariables = (): {
|
||||
dashboardVariables: IDashboardVariables;
|
||||
} => {
|
||||
const dashboardVariables = useSyncExternalStore(
|
||||
dashboardVariablesStore.subscribe,
|
||||
dashboardVariablesStore.getSnapshot,
|
||||
);
|
||||
|
||||
return {
|
||||
dashboardVariables,
|
||||
};
|
||||
};
|
||||
30
frontend/src/hooks/dashboard/useDashboardVariablesByType.ts
Normal file
30
frontend/src/hooks/dashboard/useDashboardVariablesByType.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
IDashboardVariable,
|
||||
TVariableQueryType,
|
||||
} from 'types/api/dashboard/getAll';
|
||||
|
||||
import { useDashboardVariables } from './useDashboardVariables';
|
||||
|
||||
export function useDashboardVariablesByType(
|
||||
variableType: TVariableQueryType,
|
||||
returnType: 'values',
|
||||
): IDashboardVariable[];
|
||||
export function useDashboardVariablesByType(
|
||||
variableType: TVariableQueryType,
|
||||
returnType?: 'entries',
|
||||
): [string, IDashboardVariable][];
|
||||
export function useDashboardVariablesByType(
|
||||
variableType: TVariableQueryType,
|
||||
returnType?: 'values' | 'entries',
|
||||
): IDashboardVariable[] | [string, IDashboardVariable][] {
|
||||
const { dashboardVariables } = useDashboardVariables();
|
||||
|
||||
return useMemo(() => {
|
||||
const entries = Object.entries(dashboardVariables || {}).filter(
|
||||
(entry): entry is [string, IDashboardVariable] =>
|
||||
Boolean(entry[1].name) && entry[1].type === variableType,
|
||||
);
|
||||
return returnType === 'values' ? entries.map(([, value]) => value) : entries;
|
||||
}, [dashboardVariables, variableType, returnType]);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useMemo } from 'react';
|
||||
import { PANEL_GROUP_TYPES } from 'constants/queryBuilder';
|
||||
import { createDynamicVariableToWidgetsMap } from 'hooks/dashboard/utils';
|
||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
|
||||
import { useDashboardVariablesByType } from './useDashboardVariablesByType';
|
||||
|
||||
/**
|
||||
* Hook to get a map of dynamic variable IDs to widget IDs that use them.
|
||||
* This is useful for determining which widgets need to be refreshed when a dynamic variable changes.
|
||||
*/
|
||||
export function useWidgetsByDynamicVariableId(): Record<string, string[]> {
|
||||
const dynamicVariables = useDashboardVariablesByType('DYNAMIC', 'values');
|
||||
const { selectedDashboard } = useDashboard();
|
||||
|
||||
return useMemo(() => {
|
||||
const widgets =
|
||||
selectedDashboard?.data?.widgets?.filter(
|
||||
(widget) => widget.panelTypes !== PANEL_GROUP_TYPES.ROW,
|
||||
) || [];
|
||||
|
||||
return createDynamicVariableToWidgetsMap(
|
||||
dynamicVariables,
|
||||
widgets as Widgets[],
|
||||
);
|
||||
}, [selectedDashboard, dynamicVariables]);
|
||||
}
|
||||
@@ -45,6 +45,8 @@ import APIError from 'types/api/error';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
import { useDashboardVariables } from '../../hooks/dashboard/useDashboardVariables';
|
||||
import { updateDashboardVariablesStore } from './store/dashboardVariablesStore';
|
||||
import {
|
||||
DashboardSortOrder,
|
||||
IDashboardContext,
|
||||
@@ -196,6 +198,16 @@ export function DashboardProvider({
|
||||
: isDashboardWidgetPage?.params.dashboardId) || '';
|
||||
|
||||
const [selectedDashboard, setSelectedDashboard] = useState<Dashboard>();
|
||||
const dashboardVariables = useDashboardVariables();
|
||||
|
||||
useEffect(() => {
|
||||
const existingVariables = dashboardVariables;
|
||||
const updatedVariables = selectedDashboard?.data.variables || {};
|
||||
|
||||
if (!isEqual(existingVariables, updatedVariables)) {
|
||||
updateDashboardVariablesStore(updatedVariables);
|
||||
}
|
||||
}, [selectedDashboard]);
|
||||
|
||||
const {
|
||||
currentDashboard,
|
||||
|
||||
@@ -8,6 +8,7 @@ import ROUTES from 'constants/routes';
|
||||
import { DashboardProvider, useDashboard } from 'providers/Dashboard/Dashboard';
|
||||
import { IDashboardVariable } from 'types/api/dashboard/getAll';
|
||||
|
||||
import { useDashboardVariables } from '../../../hooks/dashboard/useDashboardVariables';
|
||||
import { initializeDefaultVariables } from '../initializeDefaultVariables';
|
||||
import { normalizeUrlValueForVariable } from '../normalizeUrlValue';
|
||||
|
||||
@@ -55,6 +56,7 @@ jest.mock('uuid', () => ({ v4: jest.fn(() => 'mock-uuid') }));
|
||||
|
||||
function TestComponent(): JSX.Element {
|
||||
const { dashboardResponse, dashboardId, selectedDashboard } = useDashboard();
|
||||
const { dashboardVariables } = useDashboardVariables();
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -65,9 +67,7 @@ function TestComponent(): JSX.Element {
|
||||
{dashboardResponse.isFetching.toString()}
|
||||
</div>
|
||||
<div data-testid="dashboard-variables">
|
||||
{selectedDashboard?.data?.variables
|
||||
? JSON.stringify(selectedDashboard.data.variables)
|
||||
: 'null'}
|
||||
{dashboardVariables ? JSON.stringify(dashboardVariables) : 'null'}
|
||||
</div>
|
||||
<div data-testid="dashboard-data">
|
||||
{selectedDashboard?.data?.title || 'No Title'}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { IDashboardVariable } from 'types/api/dashboard/getAll';
|
||||
|
||||
import createStore from './store';
|
||||
|
||||
// export type IDashboardVariables = DashboardData['variables'];
|
||||
export type IDashboardVariables = Record<string, IDashboardVariable>;
|
||||
|
||||
export const dashboardVariablesStore = createStore<IDashboardVariables>({});
|
||||
|
||||
export function updateDashboardVariablesStore(
|
||||
variables: Partial<IDashboardVariables>,
|
||||
): void {
|
||||
dashboardVariablesStore.update((currentVariables) => ({
|
||||
...currentVariables,
|
||||
...variables,
|
||||
}));
|
||||
}
|
||||
44
frontend/src/providers/Dashboard/store/store.ts
Normal file
44
frontend/src/providers/Dashboard/store/store.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { produce } from 'immer';
|
||||
type ListenerFn = () => void;
|
||||
|
||||
export default function createStore<T>(
|
||||
init: T,
|
||||
): {
|
||||
set: (setter: any) => void;
|
||||
update: (updater: (draft: T) => void) => void;
|
||||
subscribe: (listener: ListenerFn) => () => void;
|
||||
getSnapshot: () => T;
|
||||
} {
|
||||
let listeners: ListenerFn[] = [];
|
||||
let state = init;
|
||||
|
||||
function emitChange(): void {
|
||||
for (const listener of listeners) {
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
function set(setter: any): void {
|
||||
state = produce(state, setter);
|
||||
emitChange();
|
||||
}
|
||||
|
||||
function update(updater: (draft: T) => void): void {
|
||||
state = produce(state, updater);
|
||||
emitChange();
|
||||
}
|
||||
|
||||
return {
|
||||
set,
|
||||
update,
|
||||
subscribe(listener: ListenerFn): () => void {
|
||||
listeners = [...listeners, listener];
|
||||
return (): void => {
|
||||
listeners = listeners.filter((l) => l !== listener);
|
||||
};
|
||||
},
|
||||
getSnapshot(): T {
|
||||
return state;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -12030,6 +12030,11 @@ immediate@~3.0.5:
|
||||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
||||
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
|
||||
|
||||
immer@11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-11.1.3.tgz#78681e1deb6cec39753acf04eb16d7576c04f4d6"
|
||||
integrity sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==
|
||||
|
||||
immer@^9.0.6:
|
||||
version "9.0.21"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
|
||||
|
||||
Reference in New Issue
Block a user