mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-08 06:48:58 +08:00
Merge branch 'develop' of github.com:SigNoz/signoz into pranshuchittora/feat/y-axis-unit-selection
This commit is contained in:
commit
17738a58a2
5
.github/workflows/e2e-k3s.yaml
vendored
5
.github/workflows/e2e-k3s.yaml
vendored
@ -52,14 +52,11 @@ jobs:
|
||||
helm install my-release signoz/signoz -n platform \
|
||||
--wait \
|
||||
--timeout 10m0s \
|
||||
--set cloud=null \
|
||||
--set frontend.service.type=LoadBalancer \
|
||||
--set query-service.image.tag=$DOCKER_TAG \
|
||||
--set queryService.image.tag=$DOCKER_TAG \
|
||||
--set frontend.image.tag=$DOCKER_TAG
|
||||
|
||||
# get pods, services and the container images
|
||||
kubectl describe deploy/my-release-frontend -n platform | grep Image
|
||||
kubectl describe statefulset/my-release-query-service -n platform | grep Image
|
||||
kubectl get pods -n platform
|
||||
kubectl get svc -n platform
|
||||
|
||||
|
@ -34,8 +34,10 @@ SigNoz helps developers monitor applications and troubleshoot problems in their
|
||||
|
||||
|
||||

|
||||
|
||||
<br />
|
||||

|
||||
<br />
|
||||

|
||||
|
||||
<br /><br />
|
||||
|
||||
|
@ -1,13 +1,10 @@
|
||||
const resizeObserverLoopErrRe = /ResizeObserver loop limit exceeded/;
|
||||
|
||||
const unCaughtExpection = () => {
|
||||
const unCaughtExpection = (): void => {
|
||||
cy.on('uncaught:exception', (err) => {
|
||||
if (resizeObserverLoopErrRe.test(err.message)) {
|
||||
// returning false here prevents Cypress from
|
||||
// failing the test
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// returning false here prevents Cypress from
|
||||
// failing the test
|
||||
return !resizeObserverLoopErrRe.test(err.message);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,8 @@ import ROUTES from 'constants/routes';
|
||||
|
||||
import defaultRules from '../../fixtures/defaultRules.json';
|
||||
|
||||
const defaultRuleRoutes = `**/rules/**`;
|
||||
|
||||
describe('Alerts', () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.setItem('isLoggedIn', 'yes');
|
||||
@ -21,7 +23,7 @@ describe('Alerts', () => {
|
||||
|
||||
it('Edit Rules Page Failure', async () => {
|
||||
cy
|
||||
.intercept('**/rules/**', {
|
||||
.intercept(defaultRuleRoutes, {
|
||||
statusCode: 500,
|
||||
})
|
||||
.as('Get Rules Error');
|
||||
@ -49,7 +51,7 @@ describe('Alerts', () => {
|
||||
const text = 'this is the sample value';
|
||||
|
||||
cy
|
||||
.intercept('**/rules/**', {
|
||||
.intercept(defaultRuleRoutes, {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
data: {
|
||||
@ -103,7 +105,7 @@ describe('Alerts', () => {
|
||||
|
||||
it('Rules are Deleted', async () => {
|
||||
cy
|
||||
.intercept('**/rules/**', {
|
||||
.intercept(defaultRuleRoutes, {
|
||||
body: {
|
||||
data: 'Deleted',
|
||||
message: 'Success',
|
||||
|
@ -1,9 +1,15 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import ROUTES from 'constants/routes';
|
||||
import { TraceFilterEnum } from 'types/reducer/trace';
|
||||
import TableInitialResponse from '../../fixtures/trace/initialSpans.json';
|
||||
import FilterInitialResponse from '../../fixtures/trace/initialSpanFilter.json';
|
||||
import GraphInitialResponse from '../../fixtures/trace/initialAggregates.json';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceFilterEnum } from 'types/reducer/trace';
|
||||
|
||||
import GraphInitialResponse from '../../fixtures/trace/initialAggregates.json';
|
||||
import FilterInitialResponse from '../../fixtures/trace/initialSpanFilter.json';
|
||||
import TableInitialResponse from '../../fixtures/trace/initialSpans.json';
|
||||
|
||||
const allFilters = '@Filters.all';
|
||||
const allGraphs = '@Graph.all';
|
||||
const allTable = '@Table.all';
|
||||
|
||||
describe('Trace', () => {
|
||||
beforeEach(() => {
|
||||
@ -74,9 +80,9 @@ describe('Trace', () => {
|
||||
JSON.stringify(TableInitialResponse),
|
||||
);
|
||||
});
|
||||
cy.get('@Filters.all').should('have.length', 1);
|
||||
cy.get('@Graph.all').should('have.length', 1);
|
||||
cy.get('@Table.all').should('have.length', 1);
|
||||
cy.get(allFilters).should('have.length', 1);
|
||||
cy.get(allGraphs).should('have.length', 1);
|
||||
cy.get(allTable).should('have.length', 1);
|
||||
});
|
||||
|
||||
it('Clear All', () => {
|
||||
@ -102,9 +108,9 @@ describe('Trace', () => {
|
||||
cy.wait(['@Filters', '@Graph', '@Table']);
|
||||
|
||||
// insuring the api get call
|
||||
cy.get('@Filters.all').should('have.length', 2);
|
||||
cy.get('@Graph.all').should('have.length', 2);
|
||||
cy.get('@Table.all').should('have.length', 2);
|
||||
cy.get(allFilters).should('have.length', 2);
|
||||
cy.get(allGraphs).should('have.length', 2);
|
||||
cy.get(allTable).should('have.length', 2);
|
||||
|
||||
cy
|
||||
.window()
|
||||
@ -146,9 +152,9 @@ describe('Trace', () => {
|
||||
expect(tableBody.exclude[0] === 'status').to.be.true;
|
||||
});
|
||||
|
||||
cy.get('@Filters.all').should('have.length', 2);
|
||||
cy.get('@Graph.all').should('have.length', 2);
|
||||
cy.get('@Table.all').should('have.length', 2);
|
||||
cy.get(allFilters).should('have.length', 2);
|
||||
cy.get(allGraphs).should('have.length', 2);
|
||||
cy.get(allTable).should('have.length', 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,6 @@ import AppReducer from 'types/reducer/app';
|
||||
|
||||
import routes from './routes';
|
||||
|
||||
|
||||
const App = (): JSX.Element => {
|
||||
const { isLoggedIn } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
|
||||
@ -20,8 +19,8 @@ const App = (): JSX.Element => {
|
||||
<AppLayout>
|
||||
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
|
||||
<Switch>
|
||||
{routes.map(({ path, component, exact }, index) => (
|
||||
<Route key={index} exact={exact} path={path} component={component} />
|
||||
{routes.map(({ path, component, exact }) => (
|
||||
<Route key={`${path}`} exact={exact} path={path} component={component} />
|
||||
))}
|
||||
<Route
|
||||
path="/"
|
||||
@ -42,5 +41,4 @@ const App = (): JSX.Element => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default App;
|
||||
|
@ -17,8 +17,8 @@ import {
|
||||
ServicesTablePage,
|
||||
SettingsPage,
|
||||
SignupPage,
|
||||
TraceFilter,
|
||||
TraceDetail,
|
||||
TraceFilter,
|
||||
UsageExplorerPage,
|
||||
} from './pageComponents';
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { AxiosAlertManagerInstance } from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/alerts/getGroups';
|
||||
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
|
||||
|
||||
const getGroups = async (
|
||||
props: Props,
|
||||
|
@ -1,7 +1,6 @@
|
||||
const get = (key: string): string | null => {
|
||||
try {
|
||||
const value = localStorage.getItem(key);
|
||||
return value;
|
||||
return localStorage.getItem(key);
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import omitBy from 'lodash-es/omitBy';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/trace/getFilters';
|
||||
import omitBy from 'lodash-es/omitBy';
|
||||
|
||||
const getFilters = async (
|
||||
props: Props,
|
||||
|
@ -2,7 +2,7 @@ import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { Props, PayloadProps } from 'types/api/trace/getTraceItem';
|
||||
import { PayloadProps, Props } from 'types/api/trace/getTraceItem';
|
||||
|
||||
const getTraceItem = async (
|
||||
props: Props,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
const TimeSeries = (props: TimeSeriesProps): JSX.Element => (
|
||||
const TimeSeries = (): JSX.Element => (
|
||||
<React.Fragment>
|
||||
<svg
|
||||
width="81"
|
||||
@ -34,9 +34,4 @@ const TimeSeries = (props: TimeSeriesProps): JSX.Element => (
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
export interface TimeSeriesProps{
|
||||
fillColor: React.CSSProperties['color'];
|
||||
}
|
||||
|
||||
|
||||
export default TimeSeries;
|
||||
|
@ -1,24 +1,25 @@
|
||||
import React from 'react';
|
||||
|
||||
const Value = (props: ValueProps): JSX.Element => {
|
||||
return(
|
||||
<React.Fragment>
|
||||
<svg
|
||||
width="78"
|
||||
height="32"
|
||||
viewBox="0 0 78 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.0215 17.875C14.2285 18.8184 13.2783 19.5771 12.1709 20.1514C11.0771 20.7256 9.87402 21.0127 8.56152 21.0127C6.83887 21.0127 5.33496 20.5889 4.0498 19.7412C2.77832 18.8936 1.79395 17.7041 1.09668 16.1729C0.399414 14.6279 0.0507812 12.9258 0.0507812 11.0664C0.0507812 9.07031 0.426758 7.27246 1.17871 5.67285C1.94434 4.07324 3.02441 2.84961 4.41895 2.00195C5.81348 1.1543 7.44043 0.730469 9.2998 0.730469C12.2529 0.730469 14.5771 1.83789 16.2725 4.05273C17.9814 6.25391 18.8359 9.26172 18.8359 13.0762V14.1836C18.8359 19.9941 17.6875 24.2393 15.3906 26.9189C13.0938 29.585 9.62793 30.9521 4.99316 31.0205H4.25488V27.8213H5.05469C8.18555 27.7666 10.5918 26.9531 12.2734 25.3809C13.9551 23.7949 14.8711 21.293 15.0215 17.875ZM9.17676 17.875C10.4482 17.875 11.6172 17.4854 12.6836 16.7061C13.7637 15.9268 14.5498 14.9629 15.042 13.8145V12.2969C15.042 9.80859 14.502 7.78516 13.4219 6.22656C12.3418 4.66797 10.9746 3.88867 9.32031 3.88867C7.65234 3.88867 6.3125 4.53125 5.30078 5.81641C4.28906 7.08789 3.7832 8.76953 3.7832 10.8613C3.7832 12.8984 4.26855 14.5801 5.23926 15.9062C6.22363 17.2188 7.53613 17.875 9.17676 17.875ZM24.5371 29.0107C24.5371 28.3545 24.7285 27.8076 25.1113 27.3701C25.5078 26.9326 26.0957 26.7139 26.875 26.7139C27.6543 26.7139 28.2422 26.9326 28.6387 27.3701C29.0488 27.8076 29.2539 28.3545 29.2539 29.0107C29.2539 29.6396 29.0488 30.166 28.6387 30.5898C28.2422 31.0137 27.6543 31.2256 26.875 31.2256C26.0957 31.2256 25.5078 31.0137 25.1113 30.5898C24.7285 30.166 24.5371 29.6396 24.5371 29.0107ZM51.1562 20.9717H55.2988V24.0684H51.1562V31H47.3418V24.0684H33.7451V21.833L47.1162 1.14062H51.1562V20.9717ZM38.0518 20.9717H47.3418V6.3291L46.8906 7.14941L38.0518 20.9717ZM73.6123 1.12012V4.33984H72.915C69.9619 4.39453 67.6104 5.26953 65.8604 6.96484C64.1104 8.66016 63.0986 11.0459 62.8252 14.1221C64.3975 12.3174 66.5439 11.415 69.2646 11.415C71.8623 11.415 73.9336 12.3311 75.4785 14.1631C77.0371 15.9951 77.8164 18.3604 77.8164 21.2588C77.8164 24.335 76.9756 26.7959 75.2939 28.6416C73.626 30.4873 71.3838 31.4102 68.5674 31.4102C65.71 31.4102 63.3926 30.3164 61.6152 28.1289C59.8379 25.9277 58.9492 23.0977 58.9492 19.6387V18.1826C58.9492 12.6865 60.1182 8.48926 62.4561 5.59082C64.8076 2.67871 68.3008 1.18848 72.9355 1.12012H73.6123ZM68.6289 14.5732C67.3301 14.5732 66.1338 14.9629 65.04 15.7422C63.9463 16.5215 63.1875 17.499 62.7637 18.6748V20.0693C62.7637 22.5303 63.3174 24.5127 64.4248 26.0166C65.5322 27.5205 66.9131 28.2725 68.5674 28.2725C70.2764 28.2725 71.6162 27.6436 72.5869 26.3857C73.5713 25.1279 74.0635 23.4805 74.0635 21.4434C74.0635 19.3926 73.5645 17.7383 72.5664 16.4805C71.582 15.209 70.2695 14.5732 68.6289 14.5732Z"
|
||||
fill={props.fillColor}
|
||||
/>
|
||||
</svg>
|
||||
</React.Fragment>
|
||||
)};
|
||||
return (
|
||||
<React.Fragment>
|
||||
<svg
|
||||
width="78"
|
||||
height="32"
|
||||
viewBox="0 0 78 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.0215 17.875C14.2285 18.8184 13.2783 19.5771 12.1709 20.1514C11.0771 20.7256 9.87402 21.0127 8.56152 21.0127C6.83887 21.0127 5.33496 20.5889 4.0498 19.7412C2.77832 18.8936 1.79395 17.7041 1.09668 16.1729C0.399414 14.6279 0.0507812 12.9258 0.0507812 11.0664C0.0507812 9.07031 0.426758 7.27246 1.17871 5.67285C1.94434 4.07324 3.02441 2.84961 4.41895 2.00195C5.81348 1.1543 7.44043 0.730469 9.2998 0.730469C12.2529 0.730469 14.5771 1.83789 16.2725 4.05273C17.9814 6.25391 18.8359 9.26172 18.8359 13.0762V14.1836C18.8359 19.9941 17.6875 24.2393 15.3906 26.9189C13.0938 29.585 9.62793 30.9521 4.99316 31.0205H4.25488V27.8213H5.05469C8.18555 27.7666 10.5918 26.9531 12.2734 25.3809C13.9551 23.7949 14.8711 21.293 15.0215 17.875ZM9.17676 17.875C10.4482 17.875 11.6172 17.4854 12.6836 16.7061C13.7637 15.9268 14.5498 14.9629 15.042 13.8145V12.2969C15.042 9.80859 14.502 7.78516 13.4219 6.22656C12.3418 4.66797 10.9746 3.88867 9.32031 3.88867C7.65234 3.88867 6.3125 4.53125 5.30078 5.81641C4.28906 7.08789 3.7832 8.76953 3.7832 10.8613C3.7832 12.8984 4.26855 14.5801 5.23926 15.9062C6.22363 17.2188 7.53613 17.875 9.17676 17.875ZM24.5371 29.0107C24.5371 28.3545 24.7285 27.8076 25.1113 27.3701C25.5078 26.9326 26.0957 26.7139 26.875 26.7139C27.6543 26.7139 28.2422 26.9326 28.6387 27.3701C29.0488 27.8076 29.2539 28.3545 29.2539 29.0107C29.2539 29.6396 29.0488 30.166 28.6387 30.5898C28.2422 31.0137 27.6543 31.2256 26.875 31.2256C26.0957 31.2256 25.5078 31.0137 25.1113 30.5898C24.7285 30.166 24.5371 29.6396 24.5371 29.0107ZM51.1562 20.9717H55.2988V24.0684H51.1562V31H47.3418V24.0684H33.7451V21.833L47.1162 1.14062H51.1562V20.9717ZM38.0518 20.9717H47.3418V6.3291L46.8906 7.14941L38.0518 20.9717ZM73.6123 1.12012V4.33984H72.915C69.9619 4.39453 67.6104 5.26953 65.8604 6.96484C64.1104 8.66016 63.0986 11.0459 62.8252 14.1221C64.3975 12.3174 66.5439 11.415 69.2646 11.415C71.8623 11.415 73.9336 12.3311 75.4785 14.1631C77.0371 15.9951 77.8164 18.3604 77.8164 21.2588C77.8164 24.335 76.9756 26.7959 75.2939 28.6416C73.626 30.4873 71.3838 31.4102 68.5674 31.4102C65.71 31.4102 63.3926 30.3164 61.6152 28.1289C59.8379 25.9277 58.9492 23.0977 58.9492 19.6387V18.1826C58.9492 12.6865 60.1182 8.48926 62.4561 5.59082C64.8076 2.67871 68.3008 1.18848 72.9355 1.12012H73.6123ZM68.6289 14.5732C67.3301 14.5732 66.1338 14.9629 65.04 15.7422C63.9463 16.5215 63.1875 17.499 62.7637 18.6748V20.0693C62.7637 22.5303 63.3174 24.5127 64.4248 26.0166C65.5322 27.5205 66.9131 28.2725 68.5674 28.2725C70.2764 28.2725 71.6162 27.6436 72.5869 26.3857C73.5713 25.1279 74.0635 23.4805 74.0635 21.4434C74.0635 19.3926 73.5645 17.7383 72.5664 16.4805C71.582 15.209 70.2695 14.5732 68.6289 14.5732Z"
|
||||
fill={props.fillColor}
|
||||
/>
|
||||
</svg>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
interface ValueProps{
|
||||
interface ValueProps {
|
||||
fillColor: React.CSSProperties['color'];
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import generatePicker from 'antd/es/date-picker/generatePicker';
|
||||
import { Dayjs } from 'dayjs';
|
||||
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
|
||||
import generatePicker from 'antd/es/date-picker/generatePicker';
|
||||
|
||||
const DatePicker = generatePicker<Dayjs>(dayjsGenerateConfig);
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { Plugin, ChartType, Chart, ChartOptions } from 'chart.js';
|
||||
import { Chart, ChartType, Plugin } from 'chart.js';
|
||||
import { colors } from 'lib/getRandomColor';
|
||||
|
||||
const getOrCreateLegendList = (chart: Chart, id: string, isLonger: boolean) => {
|
||||
const getOrCreateLegendList = (
|
||||
chart: Chart,
|
||||
id: string,
|
||||
isLonger: boolean,
|
||||
): HTMLUListElement => {
|
||||
const legendContainer = document.getElementById(id);
|
||||
let listContainer = legendContainer?.querySelector('ul');
|
||||
|
||||
@ -27,7 +31,7 @@ const getOrCreateLegendList = (chart: Chart, id: string, isLonger: boolean) => {
|
||||
export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => {
|
||||
return {
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(chart, args, options: ChartOptions) {
|
||||
afterUpdate(chart): void {
|
||||
const ul = getOrCreateLegendList(chart, id || 'legend', isLonger);
|
||||
|
||||
// Remove old legend items
|
||||
@ -46,7 +50,7 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => {
|
||||
li.style.marginLeft = '10px';
|
||||
li.style.marginTop = '5px';
|
||||
|
||||
li.onclick = () => {
|
||||
li.onclick = (): void => {
|
||||
const { type } = chart.config;
|
||||
if (type === 'pie' || type === 'doughnut') {
|
||||
// Pie and doughnut charts only have a single dataset and visibility is per item
|
||||
|
@ -77,8 +77,8 @@ export const useXAxisTimeUnit = (data: Chart['data']): IAxisTimeConfig => {
|
||||
try {
|
||||
let minTime = Number.POSITIVE_INFINITY;
|
||||
let maxTime = Number.NEGATIVE_INFINITY;
|
||||
data?.labels?.forEach((timeStamp: any) => {
|
||||
timeStamp = Date.parse(timeStamp);
|
||||
data?.labels?.forEach((timeStamp: string | number): void => {
|
||||
if (typeof timeStamp === 'string') timeStamp = Date.parse(timeStamp);
|
||||
minTime = Math.min(timeStamp, minTime);
|
||||
maxTime = Math.max(timeStamp, maxTime);
|
||||
});
|
||||
|
@ -3,9 +3,7 @@ import { ComponentType, lazy } from 'react';
|
||||
function Loadable(importPath: {
|
||||
(): LoadableProps;
|
||||
}): React.LazyExoticComponent<LazyComponent> {
|
||||
const LazyComponent = lazy(() => importPath());
|
||||
|
||||
return LazyComponent;
|
||||
return lazy(() => importPath());
|
||||
}
|
||||
|
||||
type LazyComponent = ComponentType<Record<string, unknown>>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Tabs, TabsProps } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
import history from 'lib/history';
|
||||
|
@ -10,7 +10,7 @@ import React, { useCallback } from 'react';
|
||||
const { Paragraph } = Typography;
|
||||
|
||||
import AlertChannlesComponent from './AlertChannels';
|
||||
import { ButtonContainer, Button } from './styles';
|
||||
import { Button, ButtonContainer } from './styles';
|
||||
|
||||
const AlertChannels = (): JSX.Element => {
|
||||
const onToggleHandler = useCallback(() => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Button as ButtonComponent } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const ButtonContainer = styled.div`
|
||||
&&& {
|
||||
|
@ -7,7 +7,7 @@ import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
import { Content, Footer, Layout } from './styles';
|
||||
import { Content, Layout } from './styles';
|
||||
|
||||
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||
const { isLoggedIn } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
@ -27,8 +27,6 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||
}
|
||||
}, [isLoggedIn, isSignUpPage]);
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
{!isSignUpPage && <SideNav />}
|
||||
@ -37,7 +35,6 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||
{!isSignUpPage && <TopNav />}
|
||||
{children}
|
||||
</Content>
|
||||
{/* <Footer>{`SigNoz Inc. © ${currentYear}`}</Footer> */}
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
|
@ -16,10 +16,3 @@ export const Content = styled(LayoutComponent.Content)`
|
||||
flex-direction: column;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Footer = styled(LayoutComponent.Footer)`
|
||||
&&& {
|
||||
text-align: center;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
`;
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { Tooltip, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { SpanBorder, SpanText, SpanWrapper, SpanLine } from './styles';
|
||||
import { toFixed } from 'utils/toFixed'
|
||||
import { IIntervalUnit, resolveTimeFromInterval } from 'container/TraceDetail/utils';
|
||||
import {
|
||||
IIntervalUnit,
|
||||
resolveTimeFromInterval,
|
||||
} from 'container/TraceDetail/utils';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import React from 'react';
|
||||
import { toFixed } from 'utils/toFixed';
|
||||
|
||||
import { SpanBorder, SpanLine, SpanText, SpanWrapper } from './styles';
|
||||
interface SpanLengthProps {
|
||||
width: string;
|
||||
leftOffset: string;
|
||||
@ -16,12 +20,15 @@ interface SpanLengthProps {
|
||||
|
||||
const SpanLength = (props: SpanLengthProps): JSX.Element => {
|
||||
const { width, leftOffset, bgColor, intervalUnit } = props;
|
||||
const { isDarkMode } = useThemeMode()
|
||||
const { isDarkMode } = useThemeMode();
|
||||
return (
|
||||
<SpanWrapper>
|
||||
<SpanLine leftOffset={leftOffset} isDarkMode={isDarkMode} />
|
||||
<SpanBorder bgColor={bgColor} leftOffset={leftOffset} width={width} />
|
||||
<SpanText leftOffset={leftOffset} isDarkMode={isDarkMode}>{`${toFixed(resolveTimeFromInterval(props.inMsCount, intervalUnit), 2)} ${intervalUnit.name}`}</SpanText>
|
||||
<SpanText leftOffset={leftOffset} isDarkMode={isDarkMode}>{`${toFixed(
|
||||
resolveTimeFromInterval(props.inMsCount, intervalUnit),
|
||||
2,
|
||||
)} ${intervalUnit.name}`}</SpanText>
|
||||
</SpanWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
Container,
|
||||
Service,
|
||||
Span,
|
||||
SpanWrapper,
|
||||
SpanConnector,
|
||||
Container,
|
||||
SpanName,
|
||||
SpanWrapper,
|
||||
} from './styles';
|
||||
|
||||
const SpanNameComponent = ({
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Typography } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Span = styled(Typography.Paragraph)`
|
||||
&&& {
|
||||
|
@ -1,22 +1,25 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import { CaretDownFilled, CaretRightFilled } from '@ant-design/icons';
|
||||
import { Col, Row } from 'antd';
|
||||
import {
|
||||
IIntervalUnit,
|
||||
resolveTimeFromInterval,
|
||||
} from 'container/TraceDetail/utils';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { pushDStree } from 'store/actions';
|
||||
|
||||
import { ITraceMetaData } from '..';
|
||||
import SpanLength from '../SpanLength';
|
||||
import SpanName from '../SpanName';
|
||||
import { getMetaDataFromSpanTree, getTopLeftFromBody } from '../utils';
|
||||
import {
|
||||
CardComponent,
|
||||
CardContainer,
|
||||
CaretContainer,
|
||||
Wrapper,
|
||||
HoverCard,
|
||||
Wrapper,
|
||||
} from './styles';
|
||||
import { CaretDownFilled, CaretRightFilled } from '@ant-design/icons';
|
||||
import SpanLength from '../SpanLength';
|
||||
import SpanName from '../SpanName';
|
||||
import { pushDStree } from 'store/actions';
|
||||
import { getMetaDataFromSpanTree, getTopLeftFromBody } from '../utils';
|
||||
import { ITraceMetaData } from '..';
|
||||
import { Col, Row } from 'antd';
|
||||
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants'
|
||||
import { IIntervalUnit, resolveTimeFromInterval } from 'container/TraceDetail/utils';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
|
||||
const Trace = (props: TraceProps): JSX.Element => {
|
||||
const {
|
||||
@ -38,7 +41,7 @@ const Trace = (props: TraceProps): JSX.Element => {
|
||||
intervalUnit,
|
||||
} = props;
|
||||
|
||||
const { isDarkMode } = useThemeMode()
|
||||
const { isDarkMode } = useThemeMode();
|
||||
const [isOpen, setOpen] = useState<boolean>(activeSpanPath[level] === id);
|
||||
|
||||
const localTreeExpandInteraction = useRef<boolean | 0>(0); // Boolean is for the state of the expansion whereas the number i.e. 0 is for skipping the user interaction.
|
||||
@ -47,20 +50,18 @@ const Trace = (props: TraceProps): JSX.Element => {
|
||||
if (localTreeExpandInteraction.current !== 0) {
|
||||
setOpen(localTreeExpandInteraction.current);
|
||||
localTreeExpandInteraction.current = 0;
|
||||
} else if (!isOpen) {
|
||||
setOpen(activeSpanPath[level] === id);
|
||||
}
|
||||
else if (!isOpen) {
|
||||
setOpen(activeSpanPath[level] === id)
|
||||
}
|
||||
}, [activeSpanPath, isOpen])
|
||||
}, [activeSpanPath, isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isExpandAll) {
|
||||
setOpen(isExpandAll)
|
||||
setOpen(isExpandAll);
|
||||
} else {
|
||||
setOpen(activeSpanPath[level] === id);
|
||||
}
|
||||
else {
|
||||
setOpen(activeSpanPath[level] === id)
|
||||
}
|
||||
}, [isExpandAll])
|
||||
}, [isExpandAll]);
|
||||
|
||||
const isOnlyChild = props.children.length === 1;
|
||||
const [top, setTop] = useState<number>(0);
|
||||
@ -69,9 +70,13 @@ const Trace = (props: TraceProps): JSX.Element => {
|
||||
|
||||
React.useEffect(() => {
|
||||
if (activeSelectedId === id) {
|
||||
ref.current?.scrollIntoView({ block: 'nearest', behavior: 'auto', inline: 'nearest' });
|
||||
ref.current?.scrollIntoView({
|
||||
block: 'nearest',
|
||||
behavior: 'auto',
|
||||
inline: 'nearest',
|
||||
});
|
||||
}
|
||||
}, [activeSelectedId])
|
||||
}, [activeSelectedId]);
|
||||
|
||||
const onMouseEnterHandler = () => {
|
||||
setActiveHoverId(props.id);
|
||||
@ -87,18 +92,21 @@ const Trace = (props: TraceProps): JSX.Element => {
|
||||
|
||||
const onClick = () => {
|
||||
setActiveSelectedId(id);
|
||||
}
|
||||
};
|
||||
|
||||
const onClickTreeExpansion = (event) => {
|
||||
event.stopPropagation()
|
||||
setOpen((state) => { localTreeExpandInteraction.current = !isOpen; return !state });
|
||||
}
|
||||
event.stopPropagation();
|
||||
setOpen((state) => {
|
||||
localTreeExpandInteraction.current = !isOpen;
|
||||
return !state;
|
||||
});
|
||||
};
|
||||
const { totalSpans } = getMetaDataFromSpanTree(props);
|
||||
|
||||
const inMsCount = value;
|
||||
const nodeLeftOffset = ((startTime - globalStart) * 1e2) / globalSpread;
|
||||
const width = (value * 1e2) / (globalSpread * 1e6);
|
||||
const panelWidth = SPAN_DETAILS_LEFT_COL_WIDTH - (level * (16 + 1)) - 16;
|
||||
const panelWidth = SPAN_DETAILS_LEFT_COL_WIDTH - level * (16 + 1) - 16;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -115,17 +123,12 @@ const Trace = (props: TraceProps): JSX.Element => {
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
|
||||
<CardContainer
|
||||
onClick={onClick}
|
||||
>
|
||||
<CardContainer onClick={onClick}>
|
||||
<Col flex={`${panelWidth}px`} style={{ overflow: 'hidden' }}>
|
||||
<Row style={{ flexWrap: 'nowrap' }}>
|
||||
<Col>
|
||||
{totalSpans !== 1 && (
|
||||
<CardComponent
|
||||
isDarkMode={isDarkMode}
|
||||
onClick={onClickTreeExpansion}
|
||||
>
|
||||
<CardComponent isDarkMode={isDarkMode} onClick={onClickTreeExpansion}>
|
||||
{totalSpans}
|
||||
<CaretContainer>
|
||||
{isOpen ? <CaretDownFilled /> : <CaretRightFilled />}
|
||||
@ -138,13 +141,13 @@ const Trace = (props: TraceProps): JSX.Element => {
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col flex={'1'} >
|
||||
<Col flex={'1'}>
|
||||
<SpanLength
|
||||
leftOffset={nodeLeftOffset.toString()}
|
||||
width={width.toString()}
|
||||
bgColor={serviceColour}
|
||||
id={id}
|
||||
inMsCount={(inMsCount / 1e6)}
|
||||
inMsCount={inMsCount / 1e6}
|
||||
intervalUnit={intervalUnit}
|
||||
/>
|
||||
</Col>
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { MinusSquareOutlined, PlusSquareOutlined } from '@ant-design/icons';
|
||||
import { IIntervalUnit } from 'container/TraceDetail/utils';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Trace from './Trace';
|
||||
import { MinusSquareOutlined, PlusSquareOutlined } from '@ant-design/icons'
|
||||
import { Wrapper, CardWrapper, CardContainer, CollapseButton } from './styles';
|
||||
import { getSpanPath } from './utils';
|
||||
import { IIntervalUnit } from 'container/TraceDetail/utils'
|
||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import { CardContainer, CardWrapper, CollapseButton, Wrapper } from './styles';
|
||||
import Trace from './Trace';
|
||||
import { getSpanPath } from './utils';
|
||||
|
||||
const GanttChart = (props: GanttChartProps): JSX.Element => {
|
||||
const {
|
||||
data,
|
||||
@ -15,7 +16,7 @@ const GanttChart = (props: GanttChartProps): JSX.Element => {
|
||||
activeSelectedId,
|
||||
setActiveSelectedId,
|
||||
spanId,
|
||||
intervalUnit
|
||||
intervalUnit,
|
||||
} = props;
|
||||
|
||||
const { globalStart, spread: globalSpread } = traceMetaData;
|
||||
@ -24,11 +25,11 @@ const GanttChart = (props: GanttChartProps): JSX.Element => {
|
||||
const [activeSpanPath, setActiveSpanPath] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveSpanPath(getSpanPath(data, spanId))
|
||||
setActiveSpanPath(getSpanPath(data, spanId));
|
||||
}, [spanId]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveSpanPath(getSpanPath(data, activeSelectedId))
|
||||
setActiveSpanPath(getSpanPath(data, activeSelectedId));
|
||||
}, [activeSelectedId]);
|
||||
|
||||
const handleCollapse = () => {
|
||||
@ -38,7 +39,11 @@ const GanttChart = (props: GanttChartProps): JSX.Element => {
|
||||
<>
|
||||
<Wrapper>
|
||||
<CardContainer>
|
||||
<CollapseButton onClick={handleCollapse} style={{ fontSize: '1.2rem' }} title={isExpandAll ? 'Collapse All' : "Expand All"}>
|
||||
<CollapseButton
|
||||
onClick={handleCollapse}
|
||||
style={{ fontSize: '1.2rem' }}
|
||||
title={isExpandAll ? 'Collapse All' : 'Expand All'}
|
||||
>
|
||||
{isExpandAll ? <MinusSquareOutlined /> : <PlusSquareOutlined />}
|
||||
</CollapseButton>
|
||||
<CardWrapper>
|
||||
@ -81,7 +86,7 @@ export interface GanttChartProps {
|
||||
setActiveHoverId: React.Dispatch<React.SetStateAction<string>>;
|
||||
setActiveSelectedId: React.Dispatch<React.SetStateAction<string>>;
|
||||
spanId: string;
|
||||
intervalUnit: IIntervalUnit
|
||||
intervalUnit: IIntervalUnit;
|
||||
}
|
||||
|
||||
export default GanttChart;
|
||||
|
@ -5,7 +5,7 @@ export const getMetaDataFromSpanTree = (treeData: ITraceTree) => {
|
||||
let globalEnd = Number.NEGATIVE_INFINITY;
|
||||
let totalSpans = 0;
|
||||
let levels = 1;
|
||||
const traverse = (treeNode: ITraceTree, level: number = 0) => {
|
||||
const traverse = (treeNode: ITraceTree, level = 0) => {
|
||||
if (!treeNode) {
|
||||
return;
|
||||
}
|
||||
@ -35,19 +35,19 @@ export const getMetaDataFromSpanTree = (treeData: ITraceTree) => {
|
||||
};
|
||||
|
||||
export function getTopLeftFromBody(elem: HTMLElement) {
|
||||
let box = elem.getBoundingClientRect();
|
||||
const box = elem.getBoundingClientRect();
|
||||
|
||||
let body = document.body;
|
||||
let docEl = document.documentElement;
|
||||
const body = document.body;
|
||||
const docEl = document.documentElement;
|
||||
|
||||
let scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
||||
let scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
||||
const scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
||||
const scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
||||
|
||||
let clientTop = docEl.clientTop || body.clientTop || 0;
|
||||
let clientLeft = docEl.clientLeft || body.clientLeft || 0;
|
||||
const clientTop = docEl.clientTop || body.clientTop || 0;
|
||||
const clientLeft = docEl.clientLeft || body.clientLeft || 0;
|
||||
|
||||
let top = box.top + scrollTop - clientTop;
|
||||
let left = box.left + scrollLeft - clientLeft;
|
||||
const top = box.top + scrollTop - clientTop;
|
||||
const left = box.left + scrollLeft - clientLeft;
|
||||
|
||||
return { top: Math.round(top), left: Math.round(left) };
|
||||
}
|
||||
@ -57,7 +57,7 @@ export const getNodeById = (
|
||||
treeData: ITraceTree,
|
||||
): ITraceTree | undefined => {
|
||||
let foundNode: ITraceTree | undefined = undefined;
|
||||
const traverse = (treeNode: ITraceTree, level: number = 0) => {
|
||||
const traverse = (treeNode: ITraceTree, level = 0) => {
|
||||
if (!treeNode) {
|
||||
return;
|
||||
}
|
||||
@ -115,7 +115,7 @@ export const isSpanPresent = (
|
||||
|
||||
const traverse = (
|
||||
treeNode: ITraceTree,
|
||||
level: number = 0,
|
||||
level = 0,
|
||||
foundNode: ITraceTree[],
|
||||
) => {
|
||||
if (!treeNode) {
|
||||
|
@ -23,7 +23,7 @@ import { Widgets } from 'types/api/dashboard/getAll';
|
||||
|
||||
import Bar from './Bar';
|
||||
import FullView from './FullView';
|
||||
import { Modal, FullViewContainer, ErrorContainer } from './styles';
|
||||
import { ErrorContainer, FullViewContainer, Modal } from './styles';
|
||||
|
||||
const GridCardGraph = ({
|
||||
widget,
|
||||
|
@ -7,8 +7,8 @@ const { Option } = DefaultSelect;
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
import { LOCAL_STORAGE } from 'constants/localStorage';
|
||||
import getTimeString from 'lib/getTimeString';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import getTimeString from 'lib/getTimeString';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { RouteComponentProps, withRouter } from 'react-router';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
|
@ -2,7 +2,7 @@ import { Col } from 'antd';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import React from 'react';
|
||||
import { useLocation, matchPath } from 'react-router-dom';
|
||||
import { matchPath, useLocation } from 'react-router-dom';
|
||||
|
||||
import ShowBreadcrumbs from './Breadcrumbs';
|
||||
import DateTimeSelector from './DateTimeSelection';
|
||||
|
@ -12,7 +12,7 @@ import { generatePath } from 'react-router';
|
||||
import { Alerts } from 'types/api/alerts/getAll';
|
||||
|
||||
import DeleteAlert from './DeleteAlert';
|
||||
import { ButtonContainer, Button } from './styles';
|
||||
import { Button, ButtonContainer } from './styles';
|
||||
import Status from './TableComponents/Status';
|
||||
|
||||
const ListAlert = ({ allAlertRules }: ListAlertProps): JSX.Element => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Button as ButtonComponent } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const ButtonContainer = styled.div`
|
||||
&&& {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Button } from 'antd';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import React from 'react';
|
||||
import { generatePath } from 'react-router-dom';
|
||||
import history from 'lib/history';
|
||||
|
||||
import { Data } from '..';
|
||||
|
||||
const Name = (name: Data['name'], data: Data): JSX.Element => {
|
||||
|
@ -11,7 +11,7 @@ import { AppState } from 'store/reducers';
|
||||
import DashboardReducer from 'types/reducer/dashboards';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { NewDashboardButton, TableContainer, ButtonContainer } from './styles';
|
||||
import { ButtonContainer, NewDashboardButton, TableContainer } from './styles';
|
||||
import Createdby from './TableComponents/CreatedBy';
|
||||
import DateComponent from './TableComponents/Date';
|
||||
import DeleteButton from './TableComponents/DeleteButton';
|
||||
|
@ -1,4 +1,6 @@
|
||||
import Table, { ColumnsType } from 'antd/lib/table';
|
||||
import localStorageGet from 'api/browser/localstorage/get';
|
||||
import localStorageSet from 'api/browser/localstorage/set';
|
||||
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
@ -10,8 +12,6 @@ import MetricReducer from 'types/reducer/metrics';
|
||||
|
||||
import SkipBoardModal from './SkipOnBoardModal';
|
||||
import { Container, Name } from './styles';
|
||||
import localStorageGet from 'api/browser/localstorage/get';
|
||||
import localStorageSet from 'api/browser/localstorage/set';
|
||||
|
||||
const Metrics = (): JSX.Element => {
|
||||
const [skipOnboarding, setSkipOnboarding] = useState(
|
||||
@ -31,7 +31,12 @@ const Metrics = (): JSX.Element => {
|
||||
history.push(to);
|
||||
};
|
||||
|
||||
if (services.length === 0 && loading === false && !skipOnboarding && error === true) {
|
||||
if (
|
||||
services.length === 0 &&
|
||||
loading === false &&
|
||||
!skipOnboarding &&
|
||||
error === true
|
||||
) {
|
||||
return <SkipBoardModal onContinueClick={onContinueClick} />;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ const DashboardGraphSlider = (): JSX.Element => {
|
||||
[push, pathname],
|
||||
);
|
||||
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
const fillColor:React.CSSProperties['color'] = isDarkMode?"white" : "black";
|
||||
const fillColor: React.CSSProperties['color'] = isDarkMode ? 'white' : 'black';
|
||||
return (
|
||||
<Container>
|
||||
{menuItems.map(({ name, Icon, display }) => (
|
||||
@ -37,7 +37,7 @@ const DashboardGraphSlider = (): JSX.Element => {
|
||||
key={name}
|
||||
draggable
|
||||
>
|
||||
<Icon fillColor={fillColor}/>
|
||||
<Icon fillColor={fillColor} />
|
||||
<Text>{display}</Text>
|
||||
</Card>
|
||||
))}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import TimeSeries from 'assets/Dashboard/TimeSeries';
|
||||
import ValueIcon from 'assets/Dashboard/Value';
|
||||
import { TimeSeriesProps as IconProps } from 'assets/Dashboard/TimeSeries';
|
||||
import ValueIcon from 'assets/Dashboard/Value';
|
||||
|
||||
const Items: ItemsProps[] = [
|
||||
{
|
||||
|
@ -16,10 +16,10 @@ import AppActions from 'types/actions';
|
||||
import { DeleteQueryProps } from 'types/actions/dashboard';
|
||||
|
||||
import {
|
||||
ButtonContainer,
|
||||
Container,
|
||||
InputContainer,
|
||||
QueryWrapper,
|
||||
ButtonContainer,
|
||||
} from './styles';
|
||||
|
||||
const Query = ({
|
||||
|
@ -97,7 +97,23 @@ export const dataTypeCategories = [
|
||||
{ name: 'exahashes/sec', id: 'EHs' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Misc',
|
||||
formats: [
|
||||
{ name: 'none', id: 'none' },
|
||||
{ name: 'String', id: 'string' },
|
||||
{ name: 'short', id: 'short' },
|
||||
{ name: 'Percent (0-100)', id: 'percent' },
|
||||
{ name: 'Percent (0.0-1.0)', id: 'percentunit' },
|
||||
{ name: 'Humidity (%H)', id: 'humidity' },
|
||||
{ name: 'Decibel', id: 'dB' },
|
||||
{ name: 'Hexadecimal (0x)', id: 'hex0x' },
|
||||
{ name: 'Hexadecimal', id: 'hex' },
|
||||
{ name: 'Scientific notation', id: 'sci' },
|
||||
{ name: 'Locale format', id: 'locale' },
|
||||
{ name: 'Pixels', id: 'pixel' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Acceleration',
|
||||
formats: [
|
||||
@ -364,22 +380,6 @@ export const dataTypeCategories = [
|
||||
{ name: 'On / Off', id: 'bool_on_off' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Misc',
|
||||
formats: [
|
||||
{ name: 'String', id: 'string' },
|
||||
{ name: 'short', id: 'short' },
|
||||
{ name: 'Percent (0-100)', id: 'percent' },
|
||||
{ name: 'Percent (0.0-1.0)', id: 'percentunit' },
|
||||
{ name: 'Humidity (%H)', id: 'humidity' },
|
||||
{ name: 'Decibel', id: 'dB' },
|
||||
{ name: 'Hexadecimal (0x)', id: 'hex0x' },
|
||||
{ name: 'Hexadecimal', id: 'hex' },
|
||||
{ name: 'Scientific notation', id: 'sci' },
|
||||
{ name: 'Locale format', id: 'locale' },
|
||||
{ name: 'Pixels', id: 'pixel' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
@ -77,7 +77,7 @@ const NewWidget = ({
|
||||
const [description, setDescription] = useState<string>(
|
||||
selectedWidget?.description || '',
|
||||
);
|
||||
const [yAxisUnit, setYAxisUnit] = useState<string>(selectedWidget?.yAxisUnit);
|
||||
const [yAxisUnit, setYAxisUnit] = useState<string>(selectedWidget?.yAxisUnit || 'none');
|
||||
|
||||
const [stacked, setStacked] = useState<boolean>(
|
||||
selectedWidget?.isStacked || false,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Menu, Typography } from 'antd';
|
||||
import { SlackButton, SlackMenuItemContainer, ToggleButton } from './styles';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import setTheme from 'lib/theme/setTheme';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
@ -12,11 +12,11 @@ import { ToggleDarkMode } from 'store/actions';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
import setTheme from 'lib/theme/setTheme';
|
||||
|
||||
import menus from './menuItems';
|
||||
import { Logo, Sider, ThemeSwitcherWrapper } from './styles';
|
||||
import Slack from './Slack';
|
||||
import { SlackButton, SlackMenuItemContainer, ToggleButton } from './styles';
|
||||
import { Logo, Sider, ThemeSwitcherWrapper } from './styles';
|
||||
|
||||
const SideNav = ({ toggleDarkMode }: Props): JSX.Element => {
|
||||
const [collapsed, setCollapsed] = useState<boolean>(false);
|
||||
|
@ -1,36 +1,26 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import styles from './style.module.css';
|
||||
import { useMeasure } from 'react-use';
|
||||
import { toFixed } from 'utils/toFixed';
|
||||
import {
|
||||
INTERVAL_UNITS,
|
||||
resolveTimeFromInterval,
|
||||
} from 'container/TraceDetail/utils';
|
||||
import { INTERVAL_UNITS } from 'container/TraceDetail/utils';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useMeasure } from 'react-use';
|
||||
|
||||
import styles from './style.module.css';
|
||||
import { Interval } from './types';
|
||||
import { getIntervalSpread, getIntervals } from './utils';
|
||||
interface TimelineProps {
|
||||
traceMetaData: object;
|
||||
globalTraceMetadata: object;
|
||||
intervalUnit: object;
|
||||
setIntervalUnit: Function;
|
||||
}
|
||||
import { getIntervals, getIntervalSpread } from './utils';
|
||||
|
||||
const Timeline_Height = 22;
|
||||
const Timeline_H_Spacing = 0;
|
||||
|
||||
const Timeline = ({
|
||||
traceMetaData,
|
||||
globalTraceMetadata,
|
||||
intervalUnit,
|
||||
setIntervalUnit,
|
||||
}: TimelineProps) => {
|
||||
const [ref, { width }] = useMeasure<HTMLDivElement>();
|
||||
const { isDarkMode } = useThemeMode();
|
||||
|
||||
const Timeline_Height = 22;
|
||||
const Timeline_H_Spacing = 0;
|
||||
|
||||
const [intervals, setIntervals] = useState<Interval[] | null>(null);
|
||||
|
||||
useMemo(() => {
|
||||
useEffect(() => {
|
||||
const {
|
||||
baseInterval,
|
||||
baseSpread,
|
||||
@ -44,7 +34,7 @@ const Timeline = ({
|
||||
for (const idx in INTERVAL_UNITS) {
|
||||
const standard_interval = INTERVAL_UNITS[idx];
|
||||
if (baseSpread * standard_interval.multiplier < 1) {
|
||||
intervalUnit = INTERVAL_UNITS[idx - 1];
|
||||
if (idx > 1) intervalUnit = INTERVAL_UNITS[idx - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -58,7 +48,7 @@ const Timeline = ({
|
||||
intervalUnit,
|
||||
}),
|
||||
);
|
||||
}, [traceMetaData, globalTraceMetadata]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={ref} style={{ flex: 1, overflow: 'inherit' }}>
|
||||
@ -102,4 +92,11 @@ const Timeline = ({
|
||||
);
|
||||
};
|
||||
|
||||
interface TimelineProps {
|
||||
traceMetaData: object;
|
||||
globalTraceMetadata: object;
|
||||
intervalUnit: object;
|
||||
setIntervalUnit: Function;
|
||||
}
|
||||
|
||||
export default Timeline;
|
||||
|
@ -1,20 +1,22 @@
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { toFixed } from 'utils/toFixed';
|
||||
import {
|
||||
INTERVAL_UNITS,
|
||||
resolveTimeFromInterval,
|
||||
} from 'container/TraceDetail/utils';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { toFixed } from 'utils/toFixed';
|
||||
|
||||
import { Interval } from './types';
|
||||
|
||||
export const getIntervalSpread = ({
|
||||
localTraceMetaData,
|
||||
globalTraceMetadata,
|
||||
}) => {
|
||||
const {
|
||||
globalStart: localStart,
|
||||
globalEnd: localEnd,
|
||||
spread: localSpread,
|
||||
} = localTraceMetaData;
|
||||
const { globalStart, globalEnd, globalSpread } = globalTraceMetadata;
|
||||
}): {
|
||||
baseInterval: number;
|
||||
baseSpread: number;
|
||||
intervalSpreadNormalized: number;
|
||||
} => {
|
||||
const { globalStart: localStart, spread: localSpread } = localTraceMetaData;
|
||||
const { globalStart } = globalTraceMetadata;
|
||||
|
||||
let baseInterval = 0;
|
||||
|
||||
@ -24,7 +26,7 @@ export const getIntervalSpread = ({
|
||||
|
||||
const MIN_INTERVALS = 5;
|
||||
const baseSpread = localSpread;
|
||||
let intervalSpread = (baseSpread / MIN_INTERVALS) * 1.0;
|
||||
const intervalSpread = (baseSpread / MIN_INTERVALS) * 1.0;
|
||||
const integerPartString = intervalSpread.toString().split('.')[0];
|
||||
const integerPartLength = integerPartString.length;
|
||||
const intervalSpreadNormalized =
|
||||
@ -45,7 +47,7 @@ export const getIntervals = ({
|
||||
baseSpread,
|
||||
intervalSpreadNormalized,
|
||||
intervalUnit,
|
||||
}) => {
|
||||
}): Interval[] => {
|
||||
const intervals: Interval[] = [
|
||||
{
|
||||
label: `${toFixed(resolveTimeFromInterval(baseInterval, intervalUnit), 2)}${
|
||||
|
@ -1,19 +1,19 @@
|
||||
import React, { useState } from 'react';
|
||||
import { CheckBoxContainer } from './styles';
|
||||
import { Checkbox, notification, Typography } from 'antd';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { SelectedTraceFilter } from 'store/actions/trace/selectTraceFilter';
|
||||
import AppActions from 'types/actions';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
import getFilters from 'api/trace/getFilters';
|
||||
import { AxiosError } from 'axios';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import React, { useState } from 'react';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { SelectedTraceFilter } from 'store/actions/trace/selectTraceFilter';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { CheckBoxContainer } from './styles';
|
||||
|
||||
const CheckBoxComponent = (props: CheckBoxProps): JSX.Element => {
|
||||
const {
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import CheckBoxComponent from '../Common/Checkbox';
|
||||
|
||||
const CommonCheckBox = (props: CommonCheckBoxProps): JSX.Element => {
|
||||
|
@ -1,20 +1,20 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Input, Slider } from 'antd';
|
||||
import { Container, InputContainer, Text } from './styles';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
import { SliderRangeProps } from 'antd/lib/slider';
|
||||
import getFilters from 'api/trace/getFilters';
|
||||
import dayjs from 'dayjs';
|
||||
import durationPlugin from 'dayjs/plugin/duration';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import React, { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||
import getFilters from 'api/trace/getFilters';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { SliderRangeProps } from 'antd/lib/slider';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { Container, InputContainer, Text } from './styles';
|
||||
|
||||
dayjs.extend(durationPlugin);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Typography } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const DurationText = styled.div`
|
||||
display: flex;
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
import { Card } from 'antd';
|
||||
|
||||
import Duration from './Duration';
|
||||
import CommonCheckBox from './CommonCheckBox';
|
||||
import Spinner from 'components/Spinner';
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import CommonCheckBox from './CommonCheckBox';
|
||||
import Duration from './Duration';
|
||||
|
||||
const PanelBody = (props: PanelBodyProps): JSX.Element => {
|
||||
const { type } = props;
|
||||
|
@ -1,6 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { Card, Typography, Divider, notification } from 'antd';
|
||||
import { Card, Divider, notification, Typography } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import {
|
||||
ButtonComponent,
|
||||
@ -9,19 +12,16 @@ import {
|
||||
IconContainer,
|
||||
TextCotainer,
|
||||
} from './styles';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
const { Text } = Typography;
|
||||
|
||||
import { AllPanelHeading } from 'types/reducer/trace';
|
||||
import getFilters from 'api/trace/getFilters';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Dispatch } from 'redux';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
import AppActions from 'types/actions';
|
||||
import { Dispatch } from 'redux';
|
||||
import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||
import { AxiosError } from 'axios';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { AllPanelHeading } from 'types/reducer/trace';
|
||||
|
||||
const PanelHeading = (props: PanelHeadingProps): JSX.Element => {
|
||||
const {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ChartData, ChartDataset, ChartDatasetProperties } from 'chart.js';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import dayjs from 'dayjs';
|
||||
import { colors } from 'lib/getRandomColor';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
function transposeArray(array: number[][], arrayLength: number) {
|
||||
let newArray: number[][] = [];
|
||||
const newArray: number[][] = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
newArray.push([]);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { AutoComplete, AutoCompleteProps, Input, notification } from 'antd';
|
||||
import getTagFilters from 'api/trace/getTagFilter';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
@ -18,7 +18,7 @@ const TagsKey = (props: TagsKeysProps): JSX.Element => {
|
||||
|
||||
const [options, setOptions] = useState<AutoCompleteProps['options']>([]);
|
||||
|
||||
const onSearchHandler = async () => {
|
||||
const onSearchHandler = useCallback(async () => {
|
||||
try {
|
||||
setSelectLoading(true);
|
||||
const response = await getTagFilters({
|
||||
@ -55,11 +55,16 @@ const TagsKey = (props: TagsKeysProps): JSX.Element => {
|
||||
});
|
||||
setSelectLoading(false);
|
||||
}
|
||||
};
|
||||
}, [globalTime, traces]);
|
||||
|
||||
const counter = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
onSearchHandler();
|
||||
}, []);
|
||||
if (counter.current === 0) {
|
||||
counter.current = 1;
|
||||
onSearchHandler();
|
||||
}
|
||||
}, [onSearchHandler]);
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
@ -68,7 +73,7 @@ const TagsKey = (props: TagsKeysProps): JSX.Element => {
|
||||
style={{ width: 300 }}
|
||||
options={options}
|
||||
value={selectedKey}
|
||||
onChange={(value) => {
|
||||
onChange={(value): void => {
|
||||
if (options && options.find((option) => option.value === value)) {
|
||||
setSelectedKey(value);
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Select } from 'antd';
|
||||
import { SelectValue } from 'antd/lib/select';
|
||||
import React from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { UpdateSelectedTags } from 'store/actions/trace/updateTagsSelected';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import {
|
||||
Container,
|
||||
IconContainer,
|
||||
SelectComponent,
|
||||
ValueSelect,
|
||||
} from './styles';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { SelectValue } from 'antd/lib/select';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import AppActions from 'types/actions';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { UpdateSelectedTags } from 'store/actions/trace/updateTagsSelected';
|
||||
import TagsKey from './TagKey';
|
||||
const { Option } = Select;
|
||||
|
||||
@ -45,11 +45,11 @@ const SingleTags = (props: AllTagsProps): JSX.Element => {
|
||||
Values: selectedValues,
|
||||
} = props.tag;
|
||||
|
||||
const onDeleteTagHandler = (index: number) => {
|
||||
const onDeleteTagHandler = (index: number): void => {
|
||||
props.onCloseHandler(index);
|
||||
};
|
||||
|
||||
const onChangeOperatorHandler = (key: SelectValue) => {
|
||||
const onChangeOperatorHandler = (key: SelectValue): void => {
|
||||
props.setLocalSelectedTags([
|
||||
...traces.selectedTags.slice(0, props.index),
|
||||
{
|
||||
@ -83,7 +83,7 @@ const SingleTags = (props: AllTagsProps): JSX.Element => {
|
||||
|
||||
<ValueSelect
|
||||
value={selectedValues}
|
||||
onChange={(value) => {
|
||||
onChange={(value): void => {
|
||||
props.setLocalSelectedTags((tags) => [
|
||||
...tags.slice(0, props.index),
|
||||
{
|
||||
@ -99,7 +99,7 @@ const SingleTags = (props: AllTagsProps): JSX.Element => {
|
||||
|
||||
<IconContainer
|
||||
role={'button'}
|
||||
onClick={() => onDeleteTagHandler(props.index)}
|
||||
onClick={(): void => onDeleteTagHandler(props.index)}
|
||||
>
|
||||
<CloseOutlined />
|
||||
</IconContainer>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Select, Space } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import { Button, Select, Space } from 'antd';
|
||||
|
||||
export const SpaceComponent = styled(Space)`
|
||||
&&& {
|
||||
|
@ -1,27 +1,28 @@
|
||||
import { CaretRightFilled } from '@ant-design/icons';
|
||||
import { Button, Space, Typography } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Button, Space, Typography } from 'antd';
|
||||
import { CaretRightFilled } from '@ant-design/icons';
|
||||
import {
|
||||
Container,
|
||||
ButtonContainer,
|
||||
Container,
|
||||
CurrentTagsContainer,
|
||||
Wrapper,
|
||||
ErrorContainer,
|
||||
Wrapper,
|
||||
} from './styles';
|
||||
import Tags from './Tag';
|
||||
const { Text } = Typography;
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import AppActions from 'types/actions';
|
||||
import { UpdateTagIsError } from 'store/actions/trace/updateIsTagsError';
|
||||
import { parseTagsToQuery } from '../util';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { UpdateTagVisiblity } from 'store/actions/trace/updateTagPanelVisiblity';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { parseTagsToQuery } from '../util';
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
|
||||
@ -37,7 +38,7 @@ const AllTags = ({
|
||||
TraceReducer['selectedTags']
|
||||
>(traces.selectedTags);
|
||||
|
||||
const onTagAddHandler = () => {
|
||||
const onTagAddHandler = (): void => {
|
||||
setLocalSelectedTags((tags) => [
|
||||
...tags,
|
||||
{
|
||||
@ -52,16 +53,16 @@ const AllTags = ({
|
||||
if (!isEqual(traces.selectedTags, localSelectedTags)) {
|
||||
setLocalSelectedTags(traces.selectedTags);
|
||||
}
|
||||
}, [traces.selectedTags]);
|
||||
}, [traces.selectedTags, localSelectedTags]);
|
||||
|
||||
const onCloseHandler = (index: number) => {
|
||||
const onCloseHandler = (index: number): void => {
|
||||
setLocalSelectedTags([
|
||||
...localSelectedTags.slice(0, index),
|
||||
...localSelectedTags.slice(index + 1, localSelectedTags.length),
|
||||
]);
|
||||
};
|
||||
|
||||
const onRunQueryHandler = () => {
|
||||
const onRunQueryHandler = (): void => {
|
||||
const parsedQuery = parseTagsToQuery(localSelectedTags);
|
||||
|
||||
if (parsedQuery.isError) {
|
||||
@ -74,7 +75,7 @@ const AllTags = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onResetHandler = () => {
|
||||
const onResetHandler = (): void => {
|
||||
setLocalSelectedTags([]);
|
||||
};
|
||||
|
||||
@ -102,10 +103,10 @@ const AllTags = ({
|
||||
<CurrentTagsContainer>
|
||||
{localSelectedTags.map((tags, index) => (
|
||||
<Tags
|
||||
key={index}
|
||||
key={tags.Key.join(',')}
|
||||
tag={tags}
|
||||
index={index}
|
||||
onCloseHandler={() => onCloseHandler(index)}
|
||||
onCloseHandler={(): void => onCloseHandler(index)}
|
||||
setLocalSelectedTags={setLocalSelectedTags}
|
||||
/>
|
||||
))}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Card } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Container = styled(Card)`
|
||||
top: 120%;
|
||||
|
@ -1,20 +1,21 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Space } from 'antd';
|
||||
import { Container, SearchComponent } from './styles';
|
||||
import useClickOutside from 'hooks/useClickOutside';
|
||||
import Tags from './AllTags';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import AppActions from 'types/actions';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { UpdateTagVisiblity } from 'store/actions/trace/updateTagPanelVisiblity';
|
||||
import { parseQueryToTags, parseTagsToQuery } from './util';
|
||||
import { UpdateTagIsError } from 'store/actions/trace/updateIsTagsError';
|
||||
import { CaretRightFilled } from '@ant-design/icons';
|
||||
import { Space } from 'antd';
|
||||
import useClickOutside from 'hooks/useClickOutside';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { UpdateTagIsError } from 'store/actions/trace/updateIsTagsError';
|
||||
import { UpdateTagVisiblity } from 'store/actions/trace/updateTagPanelVisiblity';
|
||||
import { updateURL } from 'store/actions/trace/util';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import Tags from './AllTags';
|
||||
import { Container, SearchComponent } from './styles';
|
||||
import { parseQueryToTags, parseTagsToQuery } from './util';
|
||||
|
||||
const Search = ({
|
||||
updateTagVisiblity,
|
||||
@ -38,7 +39,7 @@ const Search = ({
|
||||
if (value.length === 0 && traces.isTagModalError) {
|
||||
updateTagIsError(false);
|
||||
}
|
||||
}, [traces.isTagModalError, value]);
|
||||
}, [traces.isTagModalError, value, updateTagIsError]);
|
||||
|
||||
const tagRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -69,11 +70,11 @@ const Search = ({
|
||||
}
|
||||
});
|
||||
|
||||
const onChangeHandler = (search: string) => {
|
||||
const onChangeHandler = (search: string): void => {
|
||||
setValue(search);
|
||||
};
|
||||
|
||||
const setIsTagsModalHandler = (value: boolean) => {
|
||||
const setIsTagsModalHandler = (value: boolean): void => {
|
||||
updateTagVisiblity(value);
|
||||
};
|
||||
|
||||
@ -82,7 +83,9 @@ const Search = ({
|
||||
setIsTagsModalHandler(true);
|
||||
};
|
||||
|
||||
const updateFilters = async (selectedTags: TraceReducer['selectedTags']) => {
|
||||
const updateFilters = async (
|
||||
selectedTags: TraceReducer['selectedTags'],
|
||||
): Promise<void> => {
|
||||
dispatch({
|
||||
type: UPDATE_ALL_FILTERS,
|
||||
payload: {
|
||||
@ -111,7 +114,7 @@ const Search = ({
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Container ref={tagRef}>
|
||||
<SearchComponent
|
||||
onChange={(event) => onChangeHandler(event.target.value)}
|
||||
onChange={(event): void => onChangeHandler(event.target.value)}
|
||||
value={value}
|
||||
allowClear
|
||||
disabled={traces.filterLoading}
|
||||
@ -119,7 +122,7 @@ const Search = ({
|
||||
placeholder="Click to filter by tags"
|
||||
type={'search'}
|
||||
enterButton={<CaretRightFilled />}
|
||||
onSearch={(string) => {
|
||||
onSearch={(string): void => {
|
||||
if (string.length === 0) {
|
||||
updateTagVisiblity(false);
|
||||
updateFilters([]);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Input } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
|
@ -1,21 +1,22 @@
|
||||
import { SelectProps, Space } from 'antd';
|
||||
import { SelectValue } from 'antd/lib/select';
|
||||
import React from 'react';
|
||||
import { Space, SelectProps } from 'antd';
|
||||
import { functions, groupBy } from './config';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import AppActions from 'types/actions';
|
||||
import {
|
||||
UPDATE_SELECTED_FUNCTION,
|
||||
UPDATE_SELECTED_GROUP_BY,
|
||||
} from 'types/actions/trace';
|
||||
import { Dispatch } from 'redux';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { functions, groupBy } from './config';
|
||||
import { SelectComponent } from './styles';
|
||||
import { SelectValue } from 'antd/lib/select';
|
||||
|
||||
const { Option } = SelectComponent;
|
||||
|
||||
const TraceGraphFilter = () => {
|
||||
const TraceGraphFilter = (): JSX.Element => {
|
||||
const { selectedFunction, selectedGroupBy } = useSelector<
|
||||
AppState,
|
||||
TraceReducer
|
||||
@ -75,11 +76,13 @@ const TraceGraphFilter = () => {
|
||||
value={groupBy.find((e) => selectedGroupBy === e.key)?.displayValue}
|
||||
onChange={onClickSelectedGroupByHandler}
|
||||
>
|
||||
{groupBy.map((value) => (
|
||||
<Option value={value.key} key={value.key}>
|
||||
{value.displayValue}
|
||||
</Option>
|
||||
))}
|
||||
{groupBy.map(
|
||||
(value): JSX.Element => (
|
||||
<Option value={value.key} key={value.key}>
|
||||
{value.displayValue}
|
||||
</Option>
|
||||
),
|
||||
)}
|
||||
</SelectComponent>
|
||||
</Space>
|
||||
);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Select } from 'antd';
|
||||
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const SelectComponent = styled(Select)`
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Button, Modal, Collapse } from 'antd';
|
||||
import { Button, Collapse, Modal } from 'antd';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import { CustomSubText, CustomSubTitle } from './styles';
|
||||
// import Editor from 'components/Editor';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
const ErrorTag = ({ event }: ErrorTagProps) => {
|
||||
const ErrorTag = ({ event }: ErrorTagProps): JSX.Element => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const { isDarkMode } = useThemeMode();
|
||||
// const useTextRef = useRef('');
|
||||
@ -17,7 +17,7 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
||||
subText: '',
|
||||
});
|
||||
|
||||
const onToggleHandler = (state: boolean) => {
|
||||
const onToggleHandler = (state: boolean): void => {
|
||||
setIsOpen(state);
|
||||
};
|
||||
|
||||
@ -30,6 +30,7 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
||||
<Collapse
|
||||
defaultActiveKey={[name || attributeMap.event]}
|
||||
expandIconPosition="right"
|
||||
key={name}
|
||||
>
|
||||
<Panel
|
||||
header={name || attributeMap?.event}
|
||||
@ -48,7 +49,7 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
||||
{isEllipsed && (
|
||||
<Button
|
||||
style={{ padding: 0, margin: 0 }}
|
||||
onClick={() => {
|
||||
onClick={(): void => {
|
||||
onToggleHandler(true);
|
||||
setText({
|
||||
subText: value,
|
||||
@ -62,8 +63,6 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
||||
</Button>
|
||||
)}
|
||||
</CustomSubText>
|
||||
|
||||
|
||||
</>
|
||||
);
|
||||
})}
|
||||
@ -72,7 +71,7 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
||||
);
|
||||
})}
|
||||
<Modal
|
||||
onCancel={() => onToggleHandler(false)}
|
||||
onCancel={(): void => onToggleHandler(false)}
|
||||
title="Log Message"
|
||||
visible={isOpen}
|
||||
destroyOnClose
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { Space, Tabs, Typography } from 'antd';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import React from 'react';
|
||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import ErrorTag from './ErrorTag';
|
||||
import {
|
||||
CardContainer,
|
||||
CustomSubText,
|
||||
@ -8,8 +11,6 @@ import {
|
||||
CustomText,
|
||||
CustomTitle,
|
||||
} from './styles';
|
||||
import ErrorTag from './ErrorTag';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
@ -40,7 +41,7 @@ const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => {
|
||||
{tags.length !== 0 ? (
|
||||
tags.map((tags) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<React.Fragment key={tags.key}>
|
||||
{tags.value && (
|
||||
<>
|
||||
<CustomSubTitle>{tags.key}</CustomSubTitle>
|
||||
|
@ -1,21 +1,22 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Col, Divider, Row, Typography, Space, Button } from 'antd';
|
||||
import { FilterOutlined } from '@ant-design/icons';
|
||||
import { Button, Col, Divider, Row, Space, Typography } from 'antd';
|
||||
import GanttChart from 'container/GantChart';
|
||||
import { getNodeById } from 'container/GantChart/utils';
|
||||
import Timeline from 'container/Timeline';
|
||||
import TraceFlameGraph from 'container/TraceFlameGraph';
|
||||
import dayjs from 'dayjs';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { spanServiceNameToColorMapping } from 'lib/getRandomColor';
|
||||
import { getSortedData } from './utils';
|
||||
import history from 'lib/history';
|
||||
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { ITraceTree, PayloadProps } from 'types/api/trace/getTraceItem';
|
||||
import { getSpanTreeMetadata } from 'utils/getSpanTreeMetadata';
|
||||
import { spanToTreeUtil } from 'utils/spanToTree';
|
||||
|
||||
import SelectedSpanDetails from './SelectedSpanDetails';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import styles from './TraceGraph.module.css';
|
||||
import history from 'lib/history';
|
||||
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants';
|
||||
import { getSortedData } from './utils';
|
||||
import { INTERVAL_UNITS } from './utils';
|
||||
|
||||
const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
||||
@ -25,10 +26,10 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
||||
);
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
const [spanId, _setSpanId] = useState<string | null>(urlQuery.get('spanId'));
|
||||
const [spanId] = useState<string | null>(urlQuery.get('spanId'));
|
||||
|
||||
const [intervalUnit, setIntervalUnit] = useState(INTERVAL_UNITS[0]);
|
||||
const [searchSpanString, setSearchSpanString] = useState('');
|
||||
// const [searchSpanString, setSearchSpanString] = useState('');
|
||||
const [activeHoverId, setActiveHoverId] = useState<string>('');
|
||||
const [activeSelectedId, setActiveSelectedId] = useState<string>(spanId || '');
|
||||
|
||||
@ -38,9 +39,9 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
||||
|
||||
const { treeData: tree, ...traceMetaData } = useMemo(() => {
|
||||
return getSpanTreeMetadata(getSortedData(treeData), spanServiceColors);
|
||||
}, [treeData]);
|
||||
}, [treeData, spanServiceColors]);
|
||||
|
||||
const [globalTraceMetadata, _setGlobalTraceMetadata] = useState<object>({
|
||||
const [globalTraceMetadata] = useState<Record<string, number>>({
|
||||
...traceMetaData,
|
||||
});
|
||||
|
||||
@ -57,10 +58,10 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
||||
return getNodeById(activeSelectedId, treeData);
|
||||
}, [activeSelectedId, treeData]);
|
||||
|
||||
const onSearchHandler = (value: string) => {
|
||||
setSearchSpanString(value);
|
||||
setTreeData(spanToTreeUtil(response[0].events));
|
||||
};
|
||||
// const onSearchHandler = (value: string) => {
|
||||
// setSearchSpanString(value);
|
||||
// setTreeData(spanToTreeUtil(response[0].events));
|
||||
// };
|
||||
const onFocusSelectedSpanHandler = () => {
|
||||
const treeNode = getNodeById(activeSelectedId, tree);
|
||||
if (treeNode) {
|
||||
@ -68,7 +69,7 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
||||
}
|
||||
};
|
||||
|
||||
const onResetHandler = () => {
|
||||
const onResetHandler = (): void => {
|
||||
setTreeData(spanToTreeUtil(response[0].events));
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* string is present on the span or not
|
||||
*/
|
||||
import { ITraceTree, Span } from 'types/api/trace/getTraceItem';
|
||||
import { sortBy } from 'lodash-es';
|
||||
import { ITraceTree, Span } from 'types/api/trace/getTraceItem';
|
||||
|
||||
export const filterSpansByString = (
|
||||
searchString: string,
|
||||
@ -35,12 +35,12 @@ export const INTERVAL_UNITS: IIntervalUnit[] = [
|
||||
export const resolveTimeFromInterval = (
|
||||
intervalTime: number,
|
||||
intervalUnit: IIntervalUnit,
|
||||
) => {
|
||||
): number => {
|
||||
return intervalTime * intervalUnit.multiplier;
|
||||
};
|
||||
|
||||
export const getSortedData = (treeData: ITraceTree) => {
|
||||
const traverse = (treeNode: ITraceTree, level: number = 0) => {
|
||||
export const getSortedData = (treeData: ITraceTree): undefined | ITraceTree => {
|
||||
const traverse = (treeNode: ITraceTree, level = 0): void => {
|
||||
if (!treeNode) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { expect } from '@jest/globals';
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import TraceFlameGraph from 'container/TraceFlameGraph';
|
||||
import React from 'react';
|
||||
|
||||
test('loads and displays greeting', async () => {
|
||||
const { asFragment } = render(<TraceFlameGraph />);
|
||||
|
@ -1,17 +1,31 @@
|
||||
import React, { useState, useLayoutEffect, useMemo } from 'react';
|
||||
import Color from 'color';
|
||||
import { pushDStree } from 'store/actions';
|
||||
import {
|
||||
SpanItemContainer,
|
||||
TraceFlameGraphContainer,
|
||||
TOTAL_SPAN_HEIGHT,
|
||||
} from './styles';
|
||||
import { ITraceMetaData } from 'container/GantChart';
|
||||
import {
|
||||
IIntervalUnit,
|
||||
resolveTimeFromInterval,
|
||||
} from 'container/TraceDetail/utils';
|
||||
import { toFixed } from 'utils/toFixed';
|
||||
import useThemeMode from 'hooks/useThemeMode';
|
||||
import React, { useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||
import { toFixed } from 'utils/toFixed';
|
||||
|
||||
import {
|
||||
SpanItemContainer,
|
||||
TOTAL_SPAN_HEIGHT,
|
||||
TraceFlameGraphContainer,
|
||||
} from './styles';
|
||||
|
||||
interface SpanItem {
|
||||
topOffset: number;
|
||||
leftOffset: number;
|
||||
width: number;
|
||||
spanData: ITraceTree;
|
||||
tooltipText: string;
|
||||
onSpanSelect: (id: string) => void;
|
||||
onSpanHover: React.Dispatch<React.SetStateAction<string>>;
|
||||
hoveredSpanId: string;
|
||||
selectedSpanId: string;
|
||||
}
|
||||
|
||||
const SpanItem = ({
|
||||
topOffset = 0, // top offset in px
|
||||
@ -23,20 +37,10 @@ const SpanItem = ({
|
||||
onSpanHover,
|
||||
hoveredSpanId,
|
||||
selectedSpanId,
|
||||
}: {
|
||||
topOffset: number;
|
||||
leftOffset: number;
|
||||
width: number;
|
||||
spanData: pushDStree;
|
||||
tooltipText: string;
|
||||
onSpanSelect: Function;
|
||||
onSpanHover: Function;
|
||||
hoveredSpanId: string;
|
||||
selectedSpanId: string;
|
||||
}) => {
|
||||
}: SpanItem): JSX.Element => {
|
||||
const { serviceColour } = spanData;
|
||||
const [isSelected, setIsSelected] = useState<boolean>(false);
|
||||
const [isLocalHover, setIsLocalHover] = useState<boolean>(false);
|
||||
// const [isLocalHover, setIsLocalHover] = useState<boolean>(false);
|
||||
const { isDarkMode } = useThemeMode();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@ -46,16 +50,16 @@ const SpanItem = ({
|
||||
) {
|
||||
setIsSelected(true);
|
||||
}
|
||||
}, [hoveredSpanId, selectedSpanId]);
|
||||
}, [hoveredSpanId, selectedSpanId, isSelected, spanData]);
|
||||
|
||||
const handleHover = (hoverState: boolean) => {
|
||||
setIsLocalHover(hoverState);
|
||||
const handleHover = (hoverState: boolean): void => {
|
||||
// setIsLocalHover(hoverState);
|
||||
|
||||
if (hoverState) onSpanHover(spanData.id);
|
||||
else onSpanHover(null);
|
||||
else onSpanHover('');
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
const handleClick = (): void => {
|
||||
onSpanSelect(spanData.id);
|
||||
};
|
||||
|
||||
@ -64,17 +68,17 @@ const SpanItem = ({
|
||||
? Color(serviceColour).lighten(0.3)
|
||||
: Color(serviceColour).darken(0.3);
|
||||
return `${isSelected ? selectedSpanColor : serviceColour}`;
|
||||
}, [isSelected, serviceColour]);
|
||||
}, [isSelected, serviceColour, isDarkMode]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SpanItemContainer
|
||||
title={tooltipText}
|
||||
onClick={handleClick}
|
||||
onMouseEnter={() => {
|
||||
onMouseEnter={(): void => {
|
||||
handleHover(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
onMouseLeave={(): void => {
|
||||
handleHover(false);
|
||||
}}
|
||||
topOffset={topOffset}
|
||||
@ -89,26 +93,20 @@ const SpanItem = ({
|
||||
};
|
||||
|
||||
const TraceFlameGraph = (props: {
|
||||
treeData: pushDStree;
|
||||
traceMetaData: any;
|
||||
onSpanHover: Function;
|
||||
onSpanSelect: Function;
|
||||
treeData: ITraceTree;
|
||||
traceMetaData: ITraceMetaData;
|
||||
onSpanHover: SpanItem['onSpanHover'];
|
||||
onSpanSelect: SpanItem['onSpanSelect'];
|
||||
hoveredSpanId: string;
|
||||
selectedSpanId: string;
|
||||
intervalUnit: IIntervalUnit;
|
||||
}) => {
|
||||
}): JSX.Element => {
|
||||
if (!props.treeData || props.treeData.id === 'empty' || !props.traceMetaData) {
|
||||
return null;
|
||||
return <></>;
|
||||
}
|
||||
const { intervalUnit } = props;
|
||||
|
||||
const {
|
||||
globalStart,
|
||||
globalEnd,
|
||||
spread,
|
||||
totalSpans,
|
||||
levels,
|
||||
} = props.traceMetaData;
|
||||
const { globalStart, spread, levels } = props.traceMetaData;
|
||||
const RenderSpanRecursive = ({
|
||||
level = 0,
|
||||
spanData,
|
||||
@ -118,16 +116,16 @@ const TraceFlameGraph = (props: {
|
||||
hoveredSpanId,
|
||||
selectedSpanId,
|
||||
}: {
|
||||
spanData: pushDStree;
|
||||
spanData: ITraceTree;
|
||||
level?: number;
|
||||
parentLeftOffset?: number;
|
||||
onSpanHover: Function;
|
||||
onSpanSelect: Function;
|
||||
onSpanHover: SpanItem['onSpanHover'];
|
||||
onSpanSelect: SpanItem['onSpanSelect'];
|
||||
hoveredSpanId: string;
|
||||
selectedSpanId: string;
|
||||
}) => {
|
||||
}): JSX.Element => {
|
||||
if (!spanData) {
|
||||
return null;
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const leftOffset = ((spanData.startTime - globalStart) * 100) / spread;
|
||||
|
@ -16,14 +16,14 @@ export const SpanItemContainer = styled.div<{
|
||||
zIdx: number;
|
||||
}>`
|
||||
position: absolute;
|
||||
top: ${(props) => props.topOffset}px;
|
||||
left: ${(props) => props.leftOffset}%;
|
||||
width: ${(props) => props.width}%;
|
||||
top: ${(props): string | number => props.topOffset}px;
|
||||
left: ${(props): string | number => props.leftOffset}%;
|
||||
width: ${(props): string | number => props.width}%;
|
||||
height: ${SPAN_HEIGHT}px;
|
||||
margin: ${SPAN_V_PADDING}px 0;
|
||||
background-color: ${({ spanColor }) => spanColor};
|
||||
background-color: ${({ spanColor }): string | number => spanColor};
|
||||
border-radius: ${SPAN_HEIGHT / 2}px;
|
||||
z-index: ${(props) => props.zIdx};
|
||||
z-index: ${(props): string | number => props.zIdx};
|
||||
`;
|
||||
|
||||
/**
|
||||
@ -34,5 +34,5 @@ export const TraceFlameGraphContainer = styled.div<{
|
||||
}>`
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: ${({ height }) => (height ? height : 120)}px;
|
||||
height: ${({ height }): string | number => (height ? height : 120)}px;
|
||||
`;
|
||||
|
@ -1,26 +1,27 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
|
||||
const useClickOutside = (
|
||||
ref: React.RefObject<HTMLElement>,
|
||||
callback: (e: HTMLElement) => void | null,
|
||||
) => {
|
||||
const listener = (e: Event) => {
|
||||
const node = e?.target as HTMLElement;
|
||||
): void => {
|
||||
const listener = useCallback(
|
||||
(e: Event) => {
|
||||
const node = e?.target as HTMLElement;
|
||||
|
||||
if (ref.current && !ref.current.contains(node)) {
|
||||
if (callback) {
|
||||
if (ref.current && !ref.current.contains(node) && callback) {
|
||||
callback(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
[callback, ref],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', listener);
|
||||
|
||||
return () => {
|
||||
return (): void => {
|
||||
document.removeEventListener('click', listener);
|
||||
};
|
||||
}, [ref, callback]);
|
||||
}, [ref, callback, listener]);
|
||||
};
|
||||
|
||||
export default useClickOutside;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMemo, useRef } from 'react';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
import { useMemo, useRef } from 'react';
|
||||
|
||||
export interface DebouncedFunc<T extends (...args: any[]) => any> {
|
||||
export interface DebouncedFunc<T extends (...args: unknown[]) => unknown> {
|
||||
(...args: Parameters<T>): ReturnType<T> | undefined;
|
||||
|
||||
cancel(): void;
|
||||
@ -20,18 +20,17 @@ const defaultOptions: DebounceOptions = {
|
||||
trailing: true,
|
||||
};
|
||||
|
||||
const useDebouncedFn = <T extends (...args: any) => any>(
|
||||
const useDebouncedFn = <T extends (...args: Array<unknown>) => unknown>(
|
||||
fn: T,
|
||||
wait: number = 100,
|
||||
wait = 100,
|
||||
options: DebounceOptions = defaultOptions,
|
||||
dependencies?: ReadonlyArray<any>,
|
||||
): DebouncedFunc<T> => {
|
||||
const fnRef = useRef(fn);
|
||||
fnRef.current = fn;
|
||||
|
||||
return useMemo(
|
||||
() => debounce(((...args) => fnRef.current(...args)) as T, wait, options),
|
||||
[...(dependencies || [])],
|
||||
[options, wait],
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@ export interface IUseThemeModeReturn {
|
||||
isDarkMode: boolean;
|
||||
}
|
||||
|
||||
const useThemeMode = () => {
|
||||
const useThemeMode = (): IUseThemeModeReturn => {
|
||||
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
|
||||
return { isDarkMode };
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
function useUrlQuery() {
|
||||
function useUrlQuery(): URLSearchParams {
|
||||
const { search } = useLocation();
|
||||
|
||||
return useMemo(() => new URLSearchParams(search), [search]);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { span } from 'store/actions';
|
||||
import { Span } from 'types/api/trace/getTraceItem';
|
||||
|
||||
export const colors = [
|
||||
'#2F80ED',
|
||||
@ -21,7 +21,9 @@ const getRandomColor = (): string => {
|
||||
return colors[index];
|
||||
};
|
||||
|
||||
export const spanServiceNameToColorMapping = (spans: span[]) => {
|
||||
export const spanServiceNameToColorMapping = (
|
||||
spans: Span[],
|
||||
): { [key: string]: string } => {
|
||||
const serviceNameSet = new Set();
|
||||
spans.forEach((spanItem) => {
|
||||
serviceNameSet.add(spanItem[3]);
|
||||
|
@ -1,9 +1,7 @@
|
||||
const getMinAgo = ({ minutes }: getMinAgoProps): Date => {
|
||||
const currentDate = new Date();
|
||||
|
||||
const agoDate = new Date(currentDate.getTime() - minutes * 60000);
|
||||
|
||||
return agoDate;
|
||||
return new Date(currentDate.getTime() - minutes * 60000);
|
||||
};
|
||||
|
||||
interface getMinAgoProps {
|
||||
|
@ -12,7 +12,10 @@ interface GetStepInput {
|
||||
/**
|
||||
* Converts given timestamp to ms.
|
||||
*/
|
||||
const convertToMs = (timestamp: number, inputFormat: DateInputFormatType) => {
|
||||
const convertToMs = (
|
||||
timestamp: number,
|
||||
inputFormat: DateInputFormatType,
|
||||
): number => {
|
||||
switch (inputFormat) {
|
||||
case 's':
|
||||
return timestamp * 1e3;
|
||||
|
@ -1,7 +1,7 @@
|
||||
const convertObjectIntoParams = (
|
||||
props: Record<any, any>,
|
||||
props: Record<string, unknown>,
|
||||
stringify = false,
|
||||
) => {
|
||||
): string => {
|
||||
return Object.keys(props)
|
||||
.map(
|
||||
(e) =>
|
||||
|
@ -18,7 +18,7 @@ const SettingsPage = (): JSX.Element => {
|
||||
route: ROUTES.SETTINGS,
|
||||
},
|
||||
{
|
||||
Component: () => {
|
||||
Component: (): JSX.Element => {
|
||||
return <CreateAlertChannels />;
|
||||
},
|
||||
name: 'Alert Channels',
|
||||
|
@ -1,9 +1,9 @@
|
||||
import AlertChannels from 'container/AllAlertChannels';
|
||||
import GeneralSettings from 'container/GeneralSettings';
|
||||
import React from 'react';
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import AlertChannels from 'container/AllAlertChannels';
|
||||
import GeneralSettings from 'container/GeneralSettings';
|
||||
import history from 'lib/history';
|
||||
import React from 'react';
|
||||
|
||||
const AllAlertChannels = (): JSX.Element => {
|
||||
const pathName = history.location.pathname;
|
||||
|
@ -26,6 +26,9 @@ const CreateAlert = (): JSX.Element => {
|
||||
});
|
||||
const [notifications, Element] = notification.useNotification();
|
||||
|
||||
const defaultError =
|
||||
'Oops! Some issue occured in saving the alert please try again or contact support@signoz.io';
|
||||
|
||||
const onSaveHandler = useCallback(async () => {
|
||||
try {
|
||||
setNewAlertState((state) => ({
|
||||
@ -65,24 +68,19 @@ const CreateAlert = (): JSX.Element => {
|
||||
}, 3000);
|
||||
} else {
|
||||
notifications.error({
|
||||
description:
|
||||
response.error ||
|
||||
'Oops! Some issue occured in saving the alert please try again or contact support@signoz.io',
|
||||
description: response.error || defaultError,
|
||||
message: 'Error',
|
||||
});
|
||||
setNewAlertState((state) => ({
|
||||
...state,
|
||||
loading: false,
|
||||
error: true,
|
||||
errorMessage:
|
||||
response.error ||
|
||||
'Oops! Some issue occured in saving the alert please try again or contact support@signoz.io',
|
||||
errorMessage: response.error || defaultError,
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
notifications.error({
|
||||
message:
|
||||
'Oops! Some issue occured in saving the alert please try again or contact support@signoz.io',
|
||||
message: defaultError,
|
||||
});
|
||||
}
|
||||
}, [notifications]);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
||||
import MetricTable from 'container/MetricsTable';
|
||||
@ -10,7 +11,6 @@ import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
|
||||
const Metrics = ({ getService }: MetricsProps): JSX.Element => {
|
||||
const { minTime, maxTime, loading, selectedTime } = useSelector<
|
||||
|
@ -1,9 +1,9 @@
|
||||
import AlertChannels from 'container/AllAlertChannels';
|
||||
import GeneralSettings from 'container/GeneralSettings';
|
||||
import React from 'react';
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import AlertChannels from 'container/AllAlertChannels';
|
||||
import GeneralSettings from 'container/GeneralSettings';
|
||||
import history from 'lib/history';
|
||||
import React from 'react';
|
||||
|
||||
const SettingsPage = (): JSX.Element => {
|
||||
const pathName = history.location.pathname;
|
||||
|
@ -1,20 +1,23 @@
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Input,
|
||||
notification,
|
||||
Typography,
|
||||
Switch,
|
||||
Space,
|
||||
Card,
|
||||
Switch,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
import signup from 'api/user/signup';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
|
||||
import AppActions from 'types/actions';
|
||||
const { Title } = Typography;
|
||||
import setPreference from 'api/user/setPreference';
|
||||
import { IS_LOGGED_IN } from 'constants/auth';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { PayloadProps } from 'types/api/user/getUserPreference';
|
||||
|
||||
import {
|
||||
@ -26,10 +29,6 @@ import {
|
||||
Logo,
|
||||
MarginTop,
|
||||
} from './styles';
|
||||
import { IS_LOGGED_IN } from 'constants/auth';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import setPreference from 'api/user/setPreference';
|
||||
|
||||
const Signup = ({ version, userpref }: SignupProps): JSX.Element => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
@ -52,7 +51,7 @@ const Signup = ({ version, userpref }: SignupProps): JSX.Element => {
|
||||
const setState = (
|
||||
value: string,
|
||||
setFunction: React.Dispatch<React.SetStateAction<string>>,
|
||||
) => {
|
||||
): void => {
|
||||
setFunction(value);
|
||||
};
|
||||
|
||||
@ -109,7 +108,7 @@ const Signup = ({ version, userpref }: SignupProps): JSX.Element => {
|
||||
const onSwitchHandler = (
|
||||
value: boolean,
|
||||
setFunction: React.Dispatch<React.SetStateAction<boolean>>,
|
||||
) => {
|
||||
): void => {
|
||||
setFunction(value);
|
||||
};
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import React from 'react';
|
||||
import SignUpComponent from './SignUp';
|
||||
import getVersion from 'api/user/getVersion';
|
||||
import { PayloadProps as VersionPayload } from 'types/api/user/getVersion';
|
||||
import { PayloadProps as UserPrefPayload } from 'types/api/user/getUserPreference';
|
||||
|
||||
import Spinner from 'components/Spinner';
|
||||
import { Typography } from 'antd';
|
||||
import getPreference from 'api/user/getPreference';
|
||||
import getVersion from 'api/user/getVersion';
|
||||
import Spinner from 'components/Spinner';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import React from 'react';
|
||||
import { PayloadProps as UserPrefPayload } from 'types/api/user/getUserPreference';
|
||||
import { PayloadProps as VersionPayload } from 'types/api/user/getVersion';
|
||||
|
||||
const SignUp = () => {
|
||||
import SignUpComponent from './SignUp';
|
||||
|
||||
const SignUp = (): JSX.Element => {
|
||||
const versionResponse = useFetch<VersionPayload, undefined>(getVersion);
|
||||
|
||||
const userPrefResponse = useFetch<UserPrefPayload, undefined>(getPreference);
|
||||
|
@ -45,7 +45,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const MarginTop = styled.div<Props>`
|
||||
margin-top: ${({ marginTop }) => marginTop};
|
||||
margin-top: ${({ marginTop = 0 }): number | string => marginTop};
|
||||
`;
|
||||
|
||||
export const Logo = styled.img`
|
||||
|
@ -23,10 +23,10 @@ import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import {
|
||||
ClearAllFilter,
|
||||
Container,
|
||||
LeftContainer,
|
||||
RightContainer,
|
||||
ClearAllFilter,
|
||||
} from './styles';
|
||||
|
||||
const Trace = ({
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
import { Button, Card } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Container = styled.div`
|
||||
display: flex;
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import { Typography } from 'antd';
|
||||
import getTraceItem from 'api/trace/getTraceItem';
|
||||
import Spinner from 'components/Spinner';
|
||||
import TraceDetailContainer from 'container/TraceDetail';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Props as TraceDetailProps } from 'types/api/trace/getTraceItem';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { Typography } from 'antd';
|
||||
import TraceDetailContainer from 'container/TraceDetail';
|
||||
|
||||
const TraceDetail = (): JSX.Element => {
|
||||
const { id } = useParams<TraceDetailProps>();
|
||||
|
@ -6,10 +6,10 @@ import GetMaxMinTime from 'lib/getMaxMinTime';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
import GetStartAndEndTime from 'lib/getStartAndEndTime';
|
||||
import { Dispatch } from 'redux';
|
||||
import store from 'store';
|
||||
import AppActions from 'types/actions';
|
||||
import { Query } from 'types/api/dashboard/getAll';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import store from 'store';
|
||||
|
||||
export const GetQueryResults = (
|
||||
props: GetQueryResultsProps,
|
||||
|
@ -39,8 +39,6 @@ export const GetInitialData = (
|
||||
globalTime.maxTime / 1000000,
|
||||
]);
|
||||
|
||||
const step = 60;
|
||||
|
||||
const [
|
||||
// getDBOverViewResponse,
|
||||
// getExternalAverageDurationResponse,
|
||||
|
@ -1,25 +1,26 @@
|
||||
import { notification } from 'antd';
|
||||
import getFiltersApi from 'api/trace/getFilters';
|
||||
import xor from 'lodash-es/xor';
|
||||
import { Dispatch, Store } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import getFiltersApi from 'api/trace/getFilters';
|
||||
import {
|
||||
parseSelectedFilter,
|
||||
parseFilterToFetchData,
|
||||
parseQueryIntoCurrent,
|
||||
parseQueryIntoSelectedTags,
|
||||
isTraceFilterEnum,
|
||||
parseQueryIntoFilter,
|
||||
parseIsSkippedSelection,
|
||||
parseFilterExclude,
|
||||
} from './util';
|
||||
import {
|
||||
UPDATE_ALL_FILTERS,
|
||||
UPDATE_TRACE_FILTER_LOADING,
|
||||
} from 'types/actions/trace';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
import { notification } from 'antd';
|
||||
import xor from 'lodash-es/xor';
|
||||
|
||||
import {
|
||||
isTraceFilterEnum,
|
||||
parseFilterExclude,
|
||||
parseFilterToFetchData,
|
||||
parseIsSkippedSelection,
|
||||
parseQueryIntoCurrent,
|
||||
parseQueryIntoFilter,
|
||||
parseQueryIntoSelectedTags,
|
||||
parseSelectedFilter,
|
||||
} from './util';
|
||||
|
||||
export const GetInitialTraceFilter = (
|
||||
minTime: GlobalReducer['minTime'],
|
||||
@ -89,7 +90,7 @@ export const GetInitialTraceFilter = (
|
||||
isFilterExclude: getIsFilterExcluded.currentValue,
|
||||
});
|
||||
|
||||
let preSelectedFilter: Map<TraceFilterEnum, string[]> = new Map(
|
||||
const preSelectedFilter: Map<TraceFilterEnum, string[]> = new Map(
|
||||
getSelectedFilter.currentValue,
|
||||
);
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { notification } from 'antd';
|
||||
import getSpans from 'api/trace/getSpans';
|
||||
import { Dispatch, Store } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
@ -6,9 +8,7 @@ import {
|
||||
UPDATE_TRACE_GRAPH_LOADING,
|
||||
UPDATE_TRACE_GRAPH_SUCCESS,
|
||||
} from 'types/actions/trace';
|
||||
import getSpans from 'api/trace/getSpans';
|
||||
import { Props } from 'types/api/trace/getSpans';
|
||||
import { notification } from 'antd';
|
||||
|
||||
export const GetSpans = (
|
||||
props: GetSpansProps,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { ParsedUrl } from '../util';
|
||||
|
||||
export const parseQueryIntoCurrent = (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { isTraceFilterEnum, ParsedUrl } from '../util';
|
||||
|
||||
export const parseQueryIntoFilter = (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { ParsedUrl } from '../util';
|
||||
|
||||
export const parseFilterToFetchData = (
|
||||
@ -7,7 +8,7 @@ export const parseFilterToFetchData = (
|
||||
): ParsedUrl<TraceFilterEnum[]> => {
|
||||
const url = new URLSearchParams(query);
|
||||
|
||||
let filterToFetchData: TraceFilterEnum[] = [];
|
||||
const filterToFetchData: TraceFilterEnum[] = [];
|
||||
|
||||
const selected = url.get('filterToFetchData');
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
export * from './current';
|
||||
export * from './filter';
|
||||
export * from './filterToFetchData';
|
||||
export * from './isFilterExclude';
|
||||
export * from './minMaxTime';
|
||||
export * from './selectedFilter';
|
||||
export * from './filterToFetchData';
|
||||
export * from './selectedTags';
|
||||
export * from './filter';
|
||||
export * from './skippedSelected';
|
||||
export * from './current';
|
||||
export * from './isFilterExclude';
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { isTraceFilterEnum, ParsedUrl } from '../util';
|
||||
|
||||
export const parseFilterExclude = (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { isTraceFilterEnum, ParsedUrl } from '../util';
|
||||
|
||||
export const parseSelectedFilter = (
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { ParsedUrl } from '../util';
|
||||
|
||||
export const parseQueryIntoSelectedTags = (
|
||||
|
@ -2,6 +2,7 @@ import { Dispatch, Store } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { TraceFilterEnum } from 'types/reducer/trace';
|
||||
|
||||
import { updateURL } from './util';
|
||||
|
||||
export const SelectedTraceFilter = (props: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import { UPDATE_IS_TAG_ERROR } from 'types/actions/trace';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
export const UpdateTagIsError = (
|
||||
isTagModalError: TraceReducer['isTagModalError'],
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Dispatch } from 'redux';
|
||||
import AppActions from 'types/actions';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
import { UPDATE_TAG_MODAL_VISIBLITY } from 'types/actions/trace';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
export const UpdateTagVisiblity = (
|
||||
isTagModalOpen: TraceReducer['isTagModalOpen'],
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user