mirror of
https://github.com/SigNoz/signoz.git
synced 2026-04-23 04:10:29 +01:00
Compare commits
3 Commits
main
...
refactor/r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a43c15f8ed | ||
|
|
77f06094bd | ||
|
|
47078e2789 |
@@ -298,14 +298,6 @@
|
||||
"name": "react-redux",
|
||||
"message": "[State mgmt] react-redux is deprecated. Migrate to Zustand, nuqs, or react-query."
|
||||
},
|
||||
{
|
||||
"name": "xstate",
|
||||
"message": "[State mgmt] xstate is deprecated. Migrate to Zustand or react-query."
|
||||
},
|
||||
{
|
||||
"name": "@xstate/react",
|
||||
"message": "[State mgmt] @xstate/react is deprecated. Migrate to Zustand or react-query."
|
||||
},
|
||||
{
|
||||
"name": "react",
|
||||
"importNames": [
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
"@visx/shape": "3.5.0",
|
||||
"@visx/tooltip": "3.3.0",
|
||||
"@vitejs/plugin-react": "5.1.4",
|
||||
"@xstate/react": "^3.0.0",
|
||||
"ansi-to-html": "0.7.2",
|
||||
"antd": "5.11.0",
|
||||
"antd-table-saveas-excel": "2.2.1",
|
||||
@@ -147,7 +146,6 @@
|
||||
"vite": "npm:rolldown-vite@7.3.1",
|
||||
"vite-plugin-html": "3.2.2",
|
||||
"web-vitals": "^0.2.4",
|
||||
"xstate": "^4.31.0",
|
||||
"zod": "4.3.6",
|
||||
"zustand": "5.0.11"
|
||||
},
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { createMachine } from 'xstate';
|
||||
|
||||
export const ResourceAttributesFilterMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QBECGsAWAjA9qgThAAQDKYBAxhkQIIB2xAYgJYA2ALmPgHQAqqUANJgAngGIAcgFEAGr0SgADjljN2zHHQUgAHogAcAFgAM3AOz6ATAEYAzJdsA2Y4cOWAnABoQIxAFpDR2tuQ319AFYTcKdbFycAX3jvNExcAmIySmp6JjZOHn4hUTFNACFWAFd8bWVVdU1tPQQzY1MXY2tDdzNHM3dHd0NvXwR7biMTa313S0i+63DE5PRsPEJScnwqWgYiFg4uPgFhcQAlKRIpeSQQWrUNLRumx3Czbg8TR0sbS31jfUcw38fW47gBHmm4XCVms3SWIBSq3SGyyO1yBx4AHlFFxUOwcPhJLJrkoVPcGk9ENYFuF3i5YR0wtEHECEAEgiEmV8zH1DLYzHZ4Yi0utMltsrt9vluNjcfjCWVKtUbnd6o9QE1rMYBtxbGFvsZ3NrZj1WdYOfotUZLX0XEFHEKViKMpttjk9nlDrL8HiCWJzpcSbcyWrGoh3NCQj0zK53P1ph1WeFLLqnJZ2s5vmZLA6kginWsXaj3VLDoUAGqoSpgEp0cpVGohh5hhDWDy0sz8zruakzamWVm-Qyg362V5-AZOayO1KFlHitEejFHKCV6v+i5XRt1ZuU1s52zjNOOaZfdOWIY+RDZ0Hc6ZmKEXqyLPPCudit2Sz08ACSEFYNbSHI27kuquiIOEjiONwjJgrM3RWJYZisgEIJgnYPTmuEdi2OaiR5nQOAQHA2hvsiH4Sui0qFCcIGhnuLSmP0YJuJ2xjJsmKELG8XZTK0tjdHG06vgW5GupRS7St6vrKqSO4UhqVL8TBWp8o4eqdl0A5Xmy3G6gK56-B4uERDOSKiuJi6lgUAhrhUYB0buimtrEKZBDYrxaS0OZca8+ltheybOI4hivGZzrzp+VGHH+AGOQp4EIHy+ghNYnawtG4TsbYvk8QKfHGAJfQ9uF76WSW37xWBTSGJ0qXpd0vRZdEKGPqC2YeO2-zfO4+HxEAA */
|
||||
createMachine({
|
||||
tsTypes: {} as import('./Labels.machine.typegen').Typegen0,
|
||||
initial: 'Idle',
|
||||
states: {
|
||||
LabelKey: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectLabelValue',
|
||||
target: 'LabelValue',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onSelectLabelValue',
|
||||
target: 'LabelValue',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
LabelValue: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: ['onValidateQuery'],
|
||||
},
|
||||
onBlur: {
|
||||
actions: ['onValidateQuery'],
|
||||
// target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Idle: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectLabelKey',
|
||||
description: 'Enter a label key',
|
||||
target: 'LabelKey',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: 'Label Key Values',
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
// This file was automatically generated. Edits will be overwritten
|
||||
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
eventsCausingActions: {
|
||||
onSelectLabelValue: 'NEXT' | 'onBlur';
|
||||
onValidateQuery: 'NEXT' | 'onBlur';
|
||||
onSelectLabelKey: 'NEXT';
|
||||
};
|
||||
internalEvents: {
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
invokeSrcNameMap: {};
|
||||
missingImplementations: {
|
||||
actions: 'onSelectLabelValue' | 'onValidateQuery' | 'onSelectLabelKey';
|
||||
services: never;
|
||||
guards: never;
|
||||
delays: never;
|
||||
};
|
||||
eventsCausingServices: {};
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingDelays: {};
|
||||
matchesStates: 'LabelKey' | 'LabelValue' | 'Idle';
|
||||
tags: never;
|
||||
}
|
||||
@@ -4,20 +4,20 @@ import {
|
||||
CloseCircleFilled,
|
||||
ExclamationCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useMachine } from '@xstate/react';
|
||||
import { Button, Input, message, Modal } from 'antd';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { map } from 'lodash-es';
|
||||
import { Labels } from 'types/api/alerts/def';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { ResourceAttributesFilterMachine } from './Labels.machine';
|
||||
import QueryChip from './QueryChip';
|
||||
import { QueryChipItem, SearchContainer } from './styles';
|
||||
import { ILabelRecord } from './types';
|
||||
import { createQuery, flattenLabels, prepareLabels } from './utils';
|
||||
|
||||
type LabelStep = 'Idle' | 'LabelKey' | 'LabelValue';
|
||||
type LabelEvent = 'NEXT' | 'onBlur' | 'RESET';
|
||||
|
||||
interface LabelSelectProps {
|
||||
onSetLabels: (q: Labels) => void;
|
||||
initialValues: Labels | undefined;
|
||||
@@ -35,42 +35,65 @@ function LabelSelect({
|
||||
const [queries, setQueries] = useState<ILabelRecord[]>(
|
||||
initialValues ? flattenLabels(initialValues) : [],
|
||||
);
|
||||
const [step, setStep] = useState<LabelStep>('Idle');
|
||||
|
||||
const dispatchChanges = (updatedRecs: ILabelRecord[]): void => {
|
||||
onSetLabels(prepareLabels(updatedRecs, initialValues));
|
||||
setQueries(updatedRecs);
|
||||
};
|
||||
|
||||
const [state, send] = useMachine(ResourceAttributesFilterMachine, {
|
||||
actions: {
|
||||
onSelectLabelKey: () => {},
|
||||
onSelectLabelValue: () => {
|
||||
if (currentVal !== '') {
|
||||
setStaging((prevState) => [...prevState, currentVal]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
setCurrentVal('');
|
||||
},
|
||||
onValidateQuery: (): void => {
|
||||
if (currentVal === '') {
|
||||
return;
|
||||
}
|
||||
const onSelectLabelValue = (): void => {
|
||||
if (currentVal !== '') {
|
||||
setStaging((prevState) => [...prevState, currentVal]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
setCurrentVal('');
|
||||
};
|
||||
|
||||
const generatedQuery = createQuery([...staging, currentVal]);
|
||||
const onValidateQuery = (): void => {
|
||||
if (currentVal === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (generatedQuery) {
|
||||
dispatchChanges([...queries, generatedQuery]);
|
||||
setStaging([]);
|
||||
setCurrentVal('');
|
||||
send('RESET');
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
const generatedQuery = createQuery([...staging, currentVal]);
|
||||
|
||||
if (generatedQuery) {
|
||||
dispatchChanges([...queries, generatedQuery]);
|
||||
setStaging([]);
|
||||
setCurrentVal('');
|
||||
setStep('Idle');
|
||||
}
|
||||
};
|
||||
|
||||
const send = (event: LabelEvent): void => {
|
||||
if (event === 'RESET') {
|
||||
setStep('Idle');
|
||||
return;
|
||||
}
|
||||
if (event === 'NEXT') {
|
||||
if (step === 'Idle') {
|
||||
setStep('LabelKey');
|
||||
} else if (step === 'LabelKey') {
|
||||
onSelectLabelValue();
|
||||
setStep('LabelValue');
|
||||
} else if (step === 'LabelValue') {
|
||||
onValidateQuery();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event === 'onBlur') {
|
||||
if (step === 'LabelKey') {
|
||||
onSelectLabelValue();
|
||||
setStep('LabelValue');
|
||||
} else if (step === 'LabelValue') {
|
||||
onValidateQuery();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleFocus = (): void => {
|
||||
if (state.value === 'Idle') {
|
||||
if (step === 'Idle') {
|
||||
send('NEXT');
|
||||
}
|
||||
};
|
||||
@@ -79,7 +102,7 @@ function LabelSelect({
|
||||
if (staging.length === 1 && staging[0] !== undefined) {
|
||||
send('onBlur');
|
||||
}
|
||||
}, [send, staging]);
|
||||
}, [staging]);
|
||||
|
||||
useEffect(() => {
|
||||
handleBlur();
|
||||
@@ -115,14 +138,14 @@ function LabelSelect({
|
||||
});
|
||||
};
|
||||
const renderPlaceholder = useCallback((): string => {
|
||||
if (state.value === 'LabelKey') {
|
||||
if (step === 'LabelKey') {
|
||||
return 'Enter a label key then press ENTER.';
|
||||
}
|
||||
if (state.value === 'LabelValue') {
|
||||
if (step === 'LabelValue') {
|
||||
return `Enter a value for label key(${staging[0]}) then press ENTER.`;
|
||||
}
|
||||
return t('placeholder_label_key_pair');
|
||||
}, [t, state, staging]);
|
||||
}, [t, step, staging]);
|
||||
return (
|
||||
<SearchContainer isDarkMode={isDarkMode} disabled={false}>
|
||||
<div style={{ display: 'inline-flex', flexWrap: 'wrap' }}>
|
||||
@@ -148,7 +171,7 @@ function LabelSelect({
|
||||
if (e.key === 'Enter' || e.code === 'Enter' || e.key === ':') {
|
||||
send('NEXT');
|
||||
}
|
||||
if (state.value === 'Idle') {
|
||||
if (step === 'Idle') {
|
||||
send('NEXT');
|
||||
}
|
||||
}}
|
||||
@@ -159,7 +182,7 @@ function LabelSelect({
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
|
||||
{queries.length || staging.length || currentVal ? (
|
||||
{queries.length > 0 || staging.length > 0 || currentVal ? (
|
||||
<Button
|
||||
onClick={handleClearAll}
|
||||
icon={<CloseCircleFilled />}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { createMachine } from 'xstate';
|
||||
|
||||
export const DashboardSearchAndFilter = createMachine({
|
||||
tsTypes: {} as import('./Dashboard.machine.typegen').Typegen0,
|
||||
initial: 'Idle',
|
||||
states: {
|
||||
Category: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectOperator',
|
||||
target: 'Operator',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Operator: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectValue',
|
||||
target: 'Value',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Value: {
|
||||
on: {
|
||||
onBlur: {
|
||||
actions: ['onValidateQuery', 'onBlurPurge'],
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Idle: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectCategory',
|
||||
description: 'Select Category',
|
||||
target: 'Category',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: 'Dashboard Search And Filter',
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
// This file was automatically generated. Edits will be overwritten
|
||||
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
eventsCausingActions: {
|
||||
onSelectOperator: 'NEXT';
|
||||
onBlurPurge: 'onBlur';
|
||||
onSelectValue: 'NEXT';
|
||||
onValidateQuery: 'onBlur';
|
||||
onSelectCategory: 'NEXT';
|
||||
};
|
||||
internalEvents: {
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
invokeSrcNameMap: {};
|
||||
missingImplementations: {
|
||||
actions:
|
||||
| 'onSelectOperator'
|
||||
| 'onBlurPurge'
|
||||
| 'onSelectValue'
|
||||
| 'onValidateQuery'
|
||||
| 'onSelectCategory';
|
||||
services: never;
|
||||
guards: never;
|
||||
delays: never;
|
||||
};
|
||||
eventsCausingServices: {};
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingDelays: {};
|
||||
matchesStates: 'Category' | 'Operator' | 'Value' | 'Idle';
|
||||
tags: never;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { QueryChipContainer, QueryChipItem } from './styles';
|
||||
import { IQueryStructure } from './types';
|
||||
|
||||
export default function QueryChip({
|
||||
queryData,
|
||||
onRemove,
|
||||
}: {
|
||||
queryData: IQueryStructure;
|
||||
onRemove: (id: string) => void;
|
||||
}): JSX.Element {
|
||||
const { category, operator, value, id } = queryData;
|
||||
return (
|
||||
<QueryChipContainer>
|
||||
<QueryChipItem>{category}</QueryChipItem>
|
||||
<QueryChipItem>{operator}</QueryChipItem>
|
||||
<QueryChipItem closable onClose={(): void => onRemove(id)}>
|
||||
{Array.isArray(value) ? value.join(', ') : null}
|
||||
</QueryChipItem>
|
||||
</QueryChipContainer>
|
||||
);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { TOperator } from '../types';
|
||||
import { executeSearchQueries } from '../utils';
|
||||
|
||||
describe('executeSearchQueries', () => {
|
||||
const firstDashboard: Dashboard = {
|
||||
id: uuid(),
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
createdBy: '',
|
||||
updatedBy: '',
|
||||
data: {
|
||||
title: 'first dashboard',
|
||||
variables: {},
|
||||
},
|
||||
};
|
||||
const secondDashboard: Dashboard = {
|
||||
id: uuid(),
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
createdBy: '',
|
||||
updatedBy: '',
|
||||
data: {
|
||||
title: 'second dashboard',
|
||||
variables: {},
|
||||
},
|
||||
};
|
||||
const thirdDashboard: Dashboard = {
|
||||
id: uuid(),
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
createdBy: '',
|
||||
updatedBy: '',
|
||||
data: {
|
||||
title: 'third dashboard (with special characters +?\\)',
|
||||
variables: {},
|
||||
},
|
||||
};
|
||||
const dashboards = [firstDashboard, secondDashboard, thirdDashboard];
|
||||
|
||||
it('should filter dashboards based on title', () => {
|
||||
const query = {
|
||||
category: 'title',
|
||||
id: 'someid',
|
||||
operator: '=' as TOperator,
|
||||
value: 'first dashboard',
|
||||
};
|
||||
|
||||
expect(executeSearchQueries([query], dashboards)).toEqual([firstDashboard]);
|
||||
});
|
||||
|
||||
it('should filter dashboards with special characters', () => {
|
||||
const query = {
|
||||
category: 'title',
|
||||
id: 'someid',
|
||||
operator: '=' as TOperator,
|
||||
value: 'third dashboard (with special characters +?\\)',
|
||||
};
|
||||
|
||||
expect(executeSearchQueries([query], dashboards)).toEqual([thirdDashboard]);
|
||||
});
|
||||
});
|
||||
@@ -1,212 +0,0 @@
|
||||
import {
|
||||
MutableRefObject,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { CloseCircleFilled } from '@ant-design/icons';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useMachine } from '@xstate/react';
|
||||
import { Button, RefSelectProps, Select } from 'antd';
|
||||
import history from 'lib/history';
|
||||
import { filter, map } from 'lodash-es';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { DashboardSearchAndFilter } from './Dashboard.machine';
|
||||
import QueryChip from './QueryChip';
|
||||
import { QueryChipItem, SearchContainer } from './styles';
|
||||
import { IOptionsData, IQueryStructure, TCategory, TOperator } from './types';
|
||||
import {
|
||||
convertQueriesToURLQuery,
|
||||
convertURLQueryStringToQuery,
|
||||
executeSearchQueries,
|
||||
OptionsSchemas,
|
||||
OptionsValueResolution,
|
||||
} from './utils';
|
||||
|
||||
function SearchFilter({
|
||||
searchData,
|
||||
filterDashboards,
|
||||
}: {
|
||||
searchData: Dashboard[];
|
||||
filterDashboards: (filteredDashboards: Dashboard[]) => void;
|
||||
}): JSX.Element {
|
||||
const [category, setCategory] = useState<TCategory>();
|
||||
const [optionsData, setOptionsData] = useState<IOptionsData>(
|
||||
OptionsSchemas.attribute,
|
||||
);
|
||||
const selectRef = useRef() as MutableRefObject<RefSelectProps>;
|
||||
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
||||
const [staging, setStaging] = useState<string[] | string[][] | unknown[]>([]);
|
||||
const [queries, setQueries] = useState<IQueryStructure[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const searchQueryString = new URLSearchParams(history.location.search).get(
|
||||
'search',
|
||||
);
|
||||
if (searchQueryString) {
|
||||
setQueries(convertURLQueryStringToQuery(searchQueryString) || []);
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
filterDashboards(executeSearchQueries(queries, searchData));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [queries, searchData]);
|
||||
|
||||
const updateURLWithQuery = useCallback(
|
||||
(inputQueries?: IQueryStructure[]): void => {
|
||||
history.push({
|
||||
pathname: history.location.pathname,
|
||||
search:
|
||||
inputQueries || queries
|
||||
? `?search=${convertQueriesToURLQuery(inputQueries || queries)}`
|
||||
: '',
|
||||
});
|
||||
},
|
||||
[queries],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (Array.isArray(queries) && queries.length > 0) {
|
||||
updateURLWithQuery();
|
||||
}
|
||||
}, [queries, updateURLWithQuery]);
|
||||
|
||||
const [state, send] = useMachine(DashboardSearchAndFilter, {
|
||||
actions: {
|
||||
onSelectCategory: () => {
|
||||
setOptionsData(OptionsSchemas.attribute);
|
||||
},
|
||||
onSelectOperator: () => {
|
||||
setOptionsData(OptionsSchemas.operator);
|
||||
},
|
||||
onSelectValue: () => {
|
||||
setOptionsData(
|
||||
OptionsValueResolution(category as TCategory, searchData) as IOptionsData,
|
||||
);
|
||||
},
|
||||
onBlurPurge: () => {
|
||||
setSelectedValues([]);
|
||||
setStaging([]);
|
||||
},
|
||||
onValidateQuery: () => {
|
||||
if (staging.length <= 2 && selectedValues.length === 0) {
|
||||
return;
|
||||
}
|
||||
setQueries([
|
||||
...queries,
|
||||
{
|
||||
id: uuidv4(),
|
||||
category: staging[0] as string,
|
||||
operator: staging[1] as TOperator,
|
||||
value: selectedValues,
|
||||
},
|
||||
]);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const nextState = (): void => {
|
||||
send('NEXT');
|
||||
};
|
||||
|
||||
const removeQueryById = (queryId: string): void => {
|
||||
setQueries((queries) => {
|
||||
const updatedQueries = filter(queries, ({ id }) => id !== queryId);
|
||||
updateURLWithQuery(updatedQueries);
|
||||
return updatedQueries;
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = (value: never | string[]): void => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
if (optionsData.mode) {
|
||||
setSelectedValues(value.filter(Boolean));
|
||||
return;
|
||||
}
|
||||
setStaging([...staging, value]);
|
||||
|
||||
if (state.value === 'Category') {
|
||||
setCategory(`${value}`.toLowerCase() as TCategory);
|
||||
}
|
||||
nextState();
|
||||
setSelectedValues([]);
|
||||
};
|
||||
const handleFocus = (): void => {
|
||||
if (state.value === 'Idle') {
|
||||
send('NEXT');
|
||||
selectRef.current?.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = (): void => {
|
||||
send('onBlur');
|
||||
selectRef?.current?.blur();
|
||||
};
|
||||
|
||||
const clearQueries = (): void => {
|
||||
setQueries([]);
|
||||
history.push({
|
||||
pathname: history.location.pathname,
|
||||
search: ``,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<SearchContainer>
|
||||
<div>
|
||||
{map(queries, (query) => (
|
||||
<QueryChip key={query.id} queryData={query} onRemove={removeQueryById} />
|
||||
))}
|
||||
{map(staging, (value) => (
|
||||
<QueryChipItem key={JSON.stringify(value)}>
|
||||
{value as string}
|
||||
</QueryChipItem>
|
||||
))}
|
||||
</div>
|
||||
{optionsData && (
|
||||
<Select
|
||||
placeholder={
|
||||
!queries.length &&
|
||||
!staging.length &&
|
||||
!selectedValues.length &&
|
||||
'Search or Filter results'
|
||||
}
|
||||
size="small"
|
||||
ref={selectRef}
|
||||
mode={optionsData.mode as 'tags' | 'multiple'}
|
||||
style={{ flex: 1 }}
|
||||
onChange={handleChange}
|
||||
bordered={false}
|
||||
suffixIcon={null}
|
||||
value={selectedValues}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
showSearch
|
||||
>
|
||||
{optionsData.options &&
|
||||
Array.isArray(optionsData.options) &&
|
||||
optionsData.options.map(
|
||||
(optionItem): JSX.Element => (
|
||||
<Select.Option
|
||||
key={(optionItem.value as string) || (optionItem.name as string)}
|
||||
value={optionItem.value || optionItem.name}
|
||||
>
|
||||
{optionItem.name}
|
||||
</Select.Option>
|
||||
),
|
||||
)}
|
||||
</Select>
|
||||
)}
|
||||
{queries && queries.length > 0 && (
|
||||
<Button icon={<CloseCircleFilled />} type="text" onClick={clearQueries} />
|
||||
)}
|
||||
</SearchContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchFilter;
|
||||
@@ -1,27 +0,0 @@
|
||||
import { grey } from '@ant-design/colors';
|
||||
import { Tag } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const SearchContainer = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
padding: 0.2rem 0;
|
||||
margin: 1rem 0;
|
||||
border: 1px solid #ccc5;
|
||||
`;
|
||||
export const QueryChipContainer = styled.span`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 0.5rem;
|
||||
&:hover {
|
||||
& > * {
|
||||
background: ${grey.primary}44;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QueryChipItem = styled(Tag)`
|
||||
margin-right: 0.1rem;
|
||||
`;
|
||||
@@ -1,18 +0,0 @@
|
||||
export type TOperator = '=' | '!=';
|
||||
|
||||
export type TCategory = 'title' | 'description' | 'tags';
|
||||
export interface IQueryStructure {
|
||||
category: string;
|
||||
id: string;
|
||||
operator: TOperator;
|
||||
value: string | string[];
|
||||
}
|
||||
|
||||
interface IOptions {
|
||||
name: string;
|
||||
value?: string;
|
||||
}
|
||||
export interface IOptionsData {
|
||||
mode: undefined | 'tags' | 'multiple';
|
||||
options: IOptions[] | [];
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import { decode, encode } from 'js-base64';
|
||||
import { flattenDeep, map, uniqWith } from 'lodash-es';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
|
||||
import { IOptionsData, IQueryStructure, TCategory, TOperator } from './types';
|
||||
|
||||
export const convertQueriesToURLQuery = (
|
||||
queries: IQueryStructure[],
|
||||
): string => {
|
||||
if (!queries || !queries.length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return encode(JSON.stringify(queries));
|
||||
};
|
||||
|
||||
export const convertURLQueryStringToQuery = (
|
||||
queryString: string,
|
||||
): IQueryStructure[] => JSON.parse(decode(queryString));
|
||||
|
||||
export const resolveOperator = (
|
||||
result: unknown,
|
||||
operator: TOperator,
|
||||
): boolean => {
|
||||
if (operator === '!=') {
|
||||
return !result;
|
||||
}
|
||||
if (operator === '=') {
|
||||
return !!result;
|
||||
}
|
||||
return !!result;
|
||||
};
|
||||
export const executeSearchQueries = (
|
||||
queries: IQueryStructure[] = [],
|
||||
searchData: Dashboard[] = [],
|
||||
): Dashboard[] => {
|
||||
if (!searchData.length || !queries.length) {
|
||||
return searchData;
|
||||
}
|
||||
const escapeRegExp = (regExp: string): string =>
|
||||
regExp.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
queries.forEach((query: IQueryStructure) => {
|
||||
const { operator } = query;
|
||||
let { value } = query;
|
||||
const categoryLowercase: TCategory = `${query.category}`.toLowerCase() as
|
||||
| 'title'
|
||||
| 'description';
|
||||
value = flattenDeep([value]);
|
||||
|
||||
searchData = searchData.filter(({ data: searchPayload }: Dashboard) => {
|
||||
try {
|
||||
const searchSpace =
|
||||
flattenDeep([searchPayload[categoryLowercase]]).filter(Boolean) || null;
|
||||
if (!searchSpace || !searchSpace.length) {
|
||||
return resolveOperator(false, operator);
|
||||
}
|
||||
|
||||
for (const searchSpaceItem of searchSpace) {
|
||||
if (searchSpaceItem) {
|
||||
for (const queryValue of value) {
|
||||
if (searchSpaceItem.match(escapeRegExp(queryValue))) {
|
||||
return resolveOperator(true, operator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return resolveOperator(false, operator);
|
||||
});
|
||||
});
|
||||
return searchData;
|
||||
};
|
||||
|
||||
export const OptionsSchemas = {
|
||||
attribute: {
|
||||
mode: undefined,
|
||||
options: [
|
||||
{
|
||||
name: 'Title',
|
||||
},
|
||||
{
|
||||
name: 'Description',
|
||||
},
|
||||
{
|
||||
name: 'Tags',
|
||||
},
|
||||
],
|
||||
},
|
||||
operator: {
|
||||
mode: undefined,
|
||||
options: [
|
||||
{
|
||||
value: '=',
|
||||
name: 'Equal',
|
||||
},
|
||||
{
|
||||
name: 'Not Equal',
|
||||
value: '!=',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export function OptionsValueResolution(
|
||||
category: TCategory,
|
||||
searchData: Dashboard[],
|
||||
): Record<string, unknown> | IOptionsData {
|
||||
const OptionsValueSchema = {
|
||||
title: {
|
||||
mode: 'tags',
|
||||
options: uniqWith(
|
||||
map(searchData, (searchItem) => ({ name: searchItem.data.title })),
|
||||
(prev, next) => prev.name === next.name,
|
||||
),
|
||||
},
|
||||
description: {
|
||||
mode: 'tags',
|
||||
options: uniqWith(
|
||||
map(searchData, (searchItem) =>
|
||||
searchItem.data.description
|
||||
? {
|
||||
name: searchItem.data.description,
|
||||
value: searchItem.data.description,
|
||||
}
|
||||
: null,
|
||||
).filter(Boolean),
|
||||
(prev, next) => prev?.name === next?.name,
|
||||
),
|
||||
},
|
||||
tags: {
|
||||
mode: 'tags',
|
||||
options: uniqWith(
|
||||
map(
|
||||
flattenDeep(
|
||||
// @ts-ignore
|
||||
map(searchData, (searchItem) => searchItem.data.tags).filter(Boolean),
|
||||
),
|
||||
(tag) => ({ name: tag }),
|
||||
),
|
||||
(prev, next) => prev.name === next.name,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
OptionsValueSchema[category] ||
|
||||
({ mode: undefined, options: [] } as IOptionsData)
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useMachine } from '@xstate/react';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
@@ -12,7 +10,6 @@ import { FeatureKeys } from '../../constants/features';
|
||||
import { useAppContext } from '../../providers/App/App';
|
||||
import { whilelistedKeys } from './config';
|
||||
import { ResourceContext } from './context';
|
||||
import { ResourceAttributesFilterMachine } from './machine';
|
||||
import {
|
||||
IResourceAttribute,
|
||||
IResourceAttributeProps,
|
||||
@@ -28,6 +25,9 @@ import {
|
||||
OperatorSchema,
|
||||
} from './utils';
|
||||
|
||||
type ResourceStep = 'Idle' | 'TagKey' | 'Operator' | 'TagValue';
|
||||
type ResourceEvent = 'NEXT' | 'onBlur' | 'RESET';
|
||||
|
||||
function ResourceProvider({ children }: Props): JSX.Element {
|
||||
const { pathname } = useLocation();
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -36,6 +36,7 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
||||
const [queries, setQueries] = useState<IResourceAttribute[]>(
|
||||
getResourceAttributeQueriesFromURL(),
|
||||
);
|
||||
const [step, setStep] = useState<ResourceStep>('Idle');
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
const urlQuery = useUrlQuery();
|
||||
|
||||
@@ -75,64 +76,79 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
||||
[pathname, safeNavigate, urlQuery],
|
||||
);
|
||||
|
||||
const [state, send] = useMachine(ResourceAttributesFilterMachine, {
|
||||
actions: {
|
||||
onSelectTagKey: () => {
|
||||
handleLoading(true);
|
||||
GetTagKeys(dotMetricsEnabled)
|
||||
.then((tagKeys) => {
|
||||
const options = mappingWithRoutesAndKeys(pathname, tagKeys);
|
||||
const loadTagKeys = (): void => {
|
||||
handleLoading(true);
|
||||
GetTagKeys(dotMetricsEnabled)
|
||||
.then((tagKeys) => {
|
||||
const options = mappingWithRoutesAndKeys(pathname, tagKeys);
|
||||
setOptionsData({ options, mode: undefined });
|
||||
})
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
setOptionsData({
|
||||
options,
|
||||
mode: undefined,
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
},
|
||||
onSelectOperator: () => {
|
||||
setOptionsData({ options: OperatorSchema, mode: undefined });
|
||||
},
|
||||
onSelectTagValue: () => {
|
||||
handleLoading(true);
|
||||
const loadTagValues = (): void => {
|
||||
handleLoading(true);
|
||||
GetTagValues(staging[0])
|
||||
.then((tagValuesOptions) =>
|
||||
setOptionsData({ options: tagValuesOptions, mode: 'multiple' }),
|
||||
)
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
GetTagValues(staging[0])
|
||||
.then((tagValuesOptions) =>
|
||||
setOptionsData({ options: tagValuesOptions, mode: 'multiple' }),
|
||||
)
|
||||
.finally(() => {
|
||||
handleLoading(false);
|
||||
});
|
||||
},
|
||||
onBlurPurge: () => {
|
||||
setSelectedQueries([]);
|
||||
setStaging([]);
|
||||
},
|
||||
onValidateQuery: (): void => {
|
||||
if (staging.length < 2 || selectedQuery.length === 0) {
|
||||
return;
|
||||
}
|
||||
const handleNext = (): void => {
|
||||
if (step === 'Idle') {
|
||||
loadTagKeys();
|
||||
setStep('TagKey');
|
||||
} else if (step === 'TagKey') {
|
||||
setOptionsData({ options: OperatorSchema, mode: undefined });
|
||||
setStep('Operator');
|
||||
} else if (step === 'Operator') {
|
||||
loadTagValues();
|
||||
setStep('TagValue');
|
||||
}
|
||||
};
|
||||
|
||||
const generatedQuery = createQuery([...staging, selectedQuery]);
|
||||
const handleOnBlur = (): void => {
|
||||
if (step === 'TagValue' && staging.length >= 2 && selectedQuery.length > 0) {
|
||||
const generatedQuery = createQuery([...staging, selectedQuery]);
|
||||
if (generatedQuery) {
|
||||
dispatchQueries([...queries, generatedQuery]);
|
||||
}
|
||||
}
|
||||
if (step !== 'Idle') {
|
||||
setSelectedQueries([]);
|
||||
setStaging([]);
|
||||
setStep('Idle');
|
||||
}
|
||||
};
|
||||
|
||||
if (generatedQuery) {
|
||||
dispatchQueries([...queries, generatedQuery]);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
const send = (event: ResourceEvent): void => {
|
||||
if (event === 'RESET') {
|
||||
setStep('Idle');
|
||||
return;
|
||||
}
|
||||
if (event === 'NEXT') {
|
||||
handleNext();
|
||||
return;
|
||||
}
|
||||
if (event === 'onBlur') {
|
||||
handleOnBlur();
|
||||
}
|
||||
};
|
||||
|
||||
const handleFocus = useCallback((): void => {
|
||||
if (state.value === 'Idle') {
|
||||
if (step === 'Idle') {
|
||||
send('NEXT');
|
||||
}
|
||||
}, [send, state.value]);
|
||||
}, [step]);
|
||||
|
||||
const handleBlur = useCallback((): void => {
|
||||
send('onBlur');
|
||||
}, [send]);
|
||||
}, [step, staging, selectedQuery, queries, dispatchQueries]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(value: string): void => {
|
||||
@@ -145,7 +161,7 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
||||
|
||||
setSelectedQueries([...value]);
|
||||
},
|
||||
[optionsData.mode, send],
|
||||
[optionsData.mode, step, staging, dotMetricsEnabled, pathname],
|
||||
);
|
||||
|
||||
const handleEnvironmentChange = useCallback(
|
||||
@@ -166,9 +182,9 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
||||
dispatchQueries([...queriesCopy]);
|
||||
}
|
||||
|
||||
send('RESET');
|
||||
setStep('Idle');
|
||||
},
|
||||
[dispatchQueries, dotMetricsEnabled, queries, send],
|
||||
[dispatchQueries, dotMetricsEnabled, queries],
|
||||
);
|
||||
|
||||
const handleClose = useCallback(
|
||||
@@ -179,12 +195,12 @@ function ResourceProvider({ children }: Props): JSX.Element {
|
||||
);
|
||||
|
||||
const handleClearAll = useCallback(() => {
|
||||
send('RESET');
|
||||
setStep('Idle');
|
||||
dispatchQueries([]);
|
||||
setStaging([]);
|
||||
setQueries([]);
|
||||
setOptionsData({ mode: undefined, options: [] });
|
||||
}, [dispatchQueries, send]);
|
||||
}, [dispatchQueries]);
|
||||
|
||||
const getVisibleQueries = useMemo(() => {
|
||||
if (pathname === ROUTES.SERVICE_MAP) {
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { createMachine } from 'xstate';
|
||||
|
||||
export const ResourceAttributesFilterMachine =
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QBECGsAWAjA9qgThAAQDKYBAxhkQIIB2xAYgJYA2ALmPgHQAqqUANJgAngGIAcgFEAGrwDaABgC6iUAAccsZu2Y46akAA9EATkUB2bgEYAbBYsBWWwA5HAFkW3F7gDQgRRABaU3duFwsXAGZbWwAmF3co01jTAF80-zRMXAJiMkpqeiY2Th5+IVExfQAhVgBXfCVVJBBNbV19QxMEcys7B2c3T28-AOC4xUduKItrSbiEuNMo6zcMrPRsPEJScnwqWgYiFg4uPgFhcQAlKRIpBRVDdp09A1aevpt7J1cPLx8-kCCCCcUcURmcwWSxWa0cGxA2W2eT2hSOJTOPAA8uouKh2Dh8JJZI8WhotK8uh9EPM4tYZl4IrZHNY1rZrEDgqFwpEoi43HEnMt3NYEUjcrsCgcisdTmVuDi8QSibUGk0nq0Xp13qAerT6VFGRZmayXOzOSDJtNZrT3I44t5bHaLGKthL8vtDsUTqVzor8PjCWJbvdSc8KdrujTFgajSa2RzxpbwZDbfbHc7XTkdh60d65ecKgA1VANMDVOh1RrNcMdN6GYFBayOKw2xZ2h1eZ3+PX2+mxFzWEWmFymBxRLPIyWemUY+XF0v1cshh41zUR+vUhDNuncAdD6wjscWKIW0FTVPt9NdluT92o6Xon2Y7gASQgrHL0jka-JdapuqIPEcTcIoihxHyTh2Pa-JntyETRO4ngig6yTuBkmQgHQOAQHAhjijmD5erKvr4LWlI6sYiDJIo3Aiieh7Gk4UynkmQRRJ44TARYijJC4AJRBOmEESiUrEXOhaXKI5GRluPG0SkI7uIKhr2vaZ7Nq2cxrGByQWKYpiisJbqEWJs7PvK-qBmR67-pReq6aB1g+DEkEcaYcQaS2l7gTCqzrMZ2aiTOT4FuUAglmWMmboB258hCESmNeLgQR4jheVp8y+SlsIBZsQXTnmJEvu+n7RQBVEIEkLh0dYDFjvYjgsRlqY6bxY4GUZGRAA */
|
||||
createMachine({
|
||||
tsTypes: {} as import('./machine.typegen').Typegen0,
|
||||
initial: 'Idle',
|
||||
states: {
|
||||
TagKey: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectOperator',
|
||||
target: 'Operator',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Operator: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectTagValue',
|
||||
target: 'TagValue',
|
||||
},
|
||||
onBlur: {
|
||||
actions: 'onBlurPurge',
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
TagValue: {
|
||||
on: {
|
||||
onBlur: {
|
||||
actions: ['onValidateQuery', 'onBlurPurge'],
|
||||
target: 'Idle',
|
||||
},
|
||||
RESET: {
|
||||
target: 'Idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
Idle: {
|
||||
on: {
|
||||
NEXT: {
|
||||
actions: 'onSelectTagKey',
|
||||
description: 'Select Category',
|
||||
target: 'TagKey',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
predictableActionArguments: true,
|
||||
id: 'ResourceAttributesFilterMachine',
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
// This file was automatically generated. Edits will be overwritten
|
||||
|
||||
export interface Typegen0 {
|
||||
'@@xstate/typegen': true;
|
||||
internalEvents: {
|
||||
'xstate.init': { type: 'xstate.init' };
|
||||
};
|
||||
invokeSrcNameMap: {};
|
||||
missingImplementations: {
|
||||
actions:
|
||||
| 'onBlurPurge'
|
||||
| 'onSelectOperator'
|
||||
| 'onSelectTagKey'
|
||||
| 'onSelectTagValue'
|
||||
| 'onValidateQuery';
|
||||
delays: never;
|
||||
guards: never;
|
||||
services: never;
|
||||
};
|
||||
eventsCausingActions: {
|
||||
onBlurPurge: 'onBlur';
|
||||
onSelectOperator: 'NEXT';
|
||||
onSelectTagKey: 'NEXT';
|
||||
onSelectTagValue: 'NEXT';
|
||||
onValidateQuery: 'onBlur';
|
||||
};
|
||||
eventsCausingDelays: {};
|
||||
eventsCausingGuards: {};
|
||||
eventsCausingServices: {};
|
||||
matchesStates: 'Idle' | 'Operator' | 'TagKey' | 'TagValue';
|
||||
tags: never;
|
||||
}
|
||||
@@ -7031,14 +7031,6 @@
|
||||
resolved "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz"
|
||||
integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==
|
||||
|
||||
"@xstate/react@^3.0.0":
|
||||
version "3.2.2"
|
||||
resolved "https://registry.npmjs.org/@xstate/react/-/react-3.2.2.tgz"
|
||||
integrity sha512-feghXWLedyq8JeL13yda3XnHPZKwYDN5HPBLykpLeuNpr9178tQd2/3d0NrH6gSd0sG5mLuLeuD+ck830fgzLQ==
|
||||
dependencies:
|
||||
use-isomorphic-layout-effect "^1.1.2"
|
||||
use-sync-external-store "^1.0.0"
|
||||
|
||||
"@zxing/text-encoding@0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
|
||||
@@ -19157,11 +19149,6 @@ use-callback-ref@^1.3.3:
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-isomorphic-layout-effect@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz"
|
||||
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
|
||||
|
||||
use-memo-one@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"
|
||||
@@ -19175,11 +19162,6 @@ use-sidecar@^1.1.3:
|
||||
detect-node-es "^1.1.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
use-sync-external-store@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||
@@ -19723,11 +19705,6 @@ xss@^1.0.14:
|
||||
commander "^2.20.3"
|
||||
cssfilter "0.0.10"
|
||||
|
||||
xstate@^4.31.0:
|
||||
version "4.37.2"
|
||||
resolved "https://registry.npmjs.org/xstate/-/xstate-4.37.2.tgz"
|
||||
integrity sha512-Qm337O49CRTZ3PRyRuK6b+kvI+D3JGxXIZCTul+xEsyFCVkTFDt5jixaL1nBWcUBcaTQ9um/5CRGVItPi7fveg==
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
|
||||
|
||||
Reference in New Issue
Block a user