mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-23 18:36:16 +00:00
* feat: funnels list page basic UI * feat: get funnels list data from mock API, and handle data, loading and empty states * feat: implement funnel rename * chore: move useFunnels to hooks/TracesFunnels * feat: create traces funnels details basic page + funnel -> details redirection * fix: properly display created at in funnels list item + preventDefault * chore: add tab bar to trace funnel details page * chore: traces funnel details page overall skeleton * chore: traces funnel details results skeleton * fix: hide step count for add button only * feat: funnel details page steps and configuration (#7424) * chore: add a new tab for traces funnels * feat: funnels list page basic UI * feat: get funnels list data from mock API, and handle data, loading and empty states * feat: implement funnel rename * refactor: overall improvements * feat: implement sorting in traces funnels list page * feat: add sort column key and order to url params * chore: move useFunnels to hooks/TracesFunnels * feat: implement traces funnels search and refactor search and sort by extracting to custom hooks * chore: overall improvements to rename trace funnel modal * chore: make the rename input auto-focusable * feat: handle create funnel modal * feat: delete funnel modal and functionality * fix: fix the layout shift in funnel item caused by getContainer={false} * chore: overall improvements and use live api in traces funnels * feat: create traces funnels details basic page + funnel -> details redirection * fix: funnels traces light mode UI * fix: properly display created at in funnels list item + preventDefault * refactor: extract FunnelItemPopover into a separate component * chore: hide funnel tab from traces explorer * chore: add check to display trace funnels tab only in dev environment * chore: improve funnels modals light mode * chore: overall improvements * fix: properly pass funnel details link * chore: address PR review changes * chore: add tab bar to trace funnel details page * feat: funnel step UI with service, span, and where filters * feat: build radio button component * refactor: use the SignozRadioButton in funnel results -> step transitions radio buttons * feat: inter step config (i.e. latency type) UI * chore: improve steps header styles by removing divider width * feat: funnel steps title, description, popover UI + pass data from API * chore: update FilterSelect component to conditionally add url params and accept on change * fix: fix funnel step where clause and update the state variables for filters * chore: add support for isMultiple and fix the type in FilterSelect * feat: centralize the steps state management in StepsContent * fix: move steps state up + pass steps count from state * feat: implement auto save for updating the steps whenever any step changes * feat: implement auto save for validating steps if service name or span names change * feat: impelement funnel step removal * feat: implement add details modal for funnel steps * fix: fix the overflowing time range picker * feat: funnel details empty state * feat: add support for saving funnel description * chore: overall improvements * fix: fix the light mode styles * fix: fix the failing build + broken search UI * refactor: remove the reference of useLocation from traceFunnel item in TraceModulePage constant * fix: fix the issue of update steps getting triggered on initial render if we have filters * fix: fix the edge case of stale state causing filters to be re-added after removing * feat: funnel details page results (#7451) * feat: funnel metrics table component * feat: funnel metrics and steps transition metrics components UI * feat: funnel table component * feat: slowest traces and traces with error components * fix: overall light theme fixes * fix: fix the warning * chore: add empty and loading states to FunnelMetricsTable * feat: get overall funnel metrics from the API * fix: fix the empty state of funnel metrics table * feat: get data for slowest traces and traces with errors * fix: link trace id to trace details page * fix: get data for funnel step transition metrics and refactor the existing data fetching logic * refactor: add funnel context + overall refactoring and optimizations * refactor: move steps states to funnel context + handle empty and run funnel disabled states * feat: handle run funnel * fix: improve empty state * chore: rename isValidateStepsMutationLoading -> isValidateStepsLoading * chore: improve query key * fix: display loading state if funnel results are fetching * refactor: move steps validation fetching and states to the context API * fix: display loading state in funnel results while steps validation is fetching * fix: call validate steps API only on changing the service name or span name of any step * refactor: move validateStepsQuery key out of useEffect and update the dependencies * chore: centralize hasIncompleteSteps and run validate only if steps have service and spans * fix: handle all empty fields state + overall improvements * fix: handle long where query tags * feat: build the funnel result graph component * feat: build the funnel result graph component * feat: handle loading, error, empty states in funnel graph * fix: don't display change percentage if % is 0 * refactor: overall improvements * feat: get funnel steps graph data from API + move logic to custom hook * fix: improve empty and error states * fix: handle funnel graph legends width using css * fix: redirect to trace funnels list page on clicking delete from funnel details * fix: update the query cache while updating steps * fix: implement debounced search for funnel list search * fix: refetch steps graph data query on clicking run funnel / sync button * fix: improve the step footer spacing * chore: add gap between divider to inter-step-config * fix: handle loading state while fetching * feat: add span to funnel flow (from trace details page) (#7477) * chore: display add to funnel icon on hovering any span in trace details page * chore: add className to funnel item actions popover * feat: add funnels tab to trace details v2 tab bar * feat: add span to funnel flow * chore: hide actions popover button from funnel item in span -> funnel flows * chore: improve the funnel details UI in add span to funnel modal * fix: display empty state + don't redirect to funnels list on delete success + overall improvements * chore: add null check * fix: display add to funnel button based on feature flag * fix: display funnels tab in trace details based on feature flag * fix: remove maxTagCount * feat: change ms to ns * chore: address review comments * chore: remove feature flag and display trace funnels only in dev envirnoment * fix: handle restoring steps if updating funnel steps fail * refactor: update the get and delete funnel endpoints to adjust to the BE changes (#7697) * refactor: address review comments * fix: handle nested funnel response structure to fix missing funnel_id… (#7740) * fix: handle nested funnel response structure to fix missing funnel_id in updates Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: remove console.og Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: revert explicitly passing funnelId to updateFunnelSteps --------- Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> Co-authored-by: ahmadshaheer <ashaheerki@gmail.com> * chore: fix api endpoint Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * refactor: incorporate the recent funnel details API changes (#7760) * chore: trace funnels feedback changes (#7772) * chore: change the copy from x traces to valid traces found / not found * chore: add open funnel button in add span to funnel modal * feat: display buttons for adding step details and funnel description + copy to clipboard * feat: highlight funnel graph column based on selected (total / error span) from the legend items * chore: trace funnel changes (#7780) * refactor: handle funnels list search on frontend * refactor: use funnel steps update API for adding / updating step title and description * feat: allow selecting user's typed option in trace funnel service and span name dropdowns * chore: properly render the -> between steps in funnel results * fix: sync funnel step name with add details modal text fields --------- Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> Co-authored-by: Yunus M <myounis.ar@live.com> Co-authored-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com>
245 lines
6.3 KiB
TypeScript
245 lines
6.3 KiB
TypeScript
import { ValidateFunnelResponse } from 'api/traceFunnels';
|
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
|
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
|
import {
|
|
CustomTimeType,
|
|
Time as TimeV2,
|
|
} from 'container/TopNav/DateTimeSelectionV2/config';
|
|
import { useValidateFunnelSteps } from 'hooks/TracesFunnels/useFunnels';
|
|
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
|
import { initialStepsData } from 'pages/TracesFunnelDetails/constants';
|
|
import {
|
|
createContext,
|
|
Dispatch,
|
|
SetStateAction,
|
|
useCallback,
|
|
useContext,
|
|
useMemo,
|
|
useState,
|
|
} from 'react';
|
|
import { useQueryClient } from 'react-query';
|
|
import { useSelector } from 'react-redux';
|
|
import { AppState } from 'store/reducers';
|
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
|
import { FunnelData, FunnelStepData } from 'types/api/traceFunnels';
|
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
import { v4 } from 'uuid';
|
|
|
|
interface FunnelContextType {
|
|
startTime: number;
|
|
endTime: number;
|
|
selectedTime: CustomTimeType | Time | TimeV2;
|
|
validTracesCount: number;
|
|
funnelId: string;
|
|
steps: FunnelStepData[];
|
|
setSteps: Dispatch<SetStateAction<FunnelStepData[]>>;
|
|
initialSteps: FunnelStepData[];
|
|
handleAddStep: () => boolean;
|
|
handleStepChange: (index: number, newStep: Partial<FunnelStepData>) => void;
|
|
handleStepRemoval: (index: number) => void;
|
|
handleRunFunnel: () => void;
|
|
validationResponse:
|
|
| SuccessResponse<ValidateFunnelResponse>
|
|
| ErrorResponse
|
|
| undefined;
|
|
isValidateStepsLoading: boolean;
|
|
hasIncompleteStepFields: boolean;
|
|
setHasIncompleteStepFields: Dispatch<SetStateAction<boolean>>;
|
|
hasAllEmptyStepFields: boolean;
|
|
setHasAllEmptyStepFields: Dispatch<SetStateAction<boolean>>;
|
|
handleReplaceStep: (
|
|
index: number,
|
|
serviceName: string,
|
|
spanName: string,
|
|
) => void;
|
|
handleRestoreSteps: (oldSteps: FunnelStepData[]) => void;
|
|
}
|
|
|
|
const FunnelContext = createContext<FunnelContextType | undefined>(undefined);
|
|
|
|
export function FunnelProvider({
|
|
children,
|
|
funnelId,
|
|
}: {
|
|
children: React.ReactNode;
|
|
funnelId: string;
|
|
}): JSX.Element {
|
|
const { selectedTime } = useSelector<AppState, GlobalReducer>(
|
|
(state) => state.globalTime,
|
|
);
|
|
const { start, end } = getStartEndRangeTime({
|
|
type: 'GLOBAL_TIME',
|
|
interval: selectedTime,
|
|
});
|
|
|
|
const startTime = Math.floor(Number(start) * 1e9);
|
|
const endTime = Math.floor(Number(end) * 1e9);
|
|
|
|
const queryClient = useQueryClient();
|
|
const data = queryClient.getQueryData<{ payload: FunnelData }>([
|
|
REACT_QUERY_KEY.GET_FUNNEL_DETAILS,
|
|
funnelId,
|
|
]);
|
|
const funnel = data?.payload;
|
|
const initialSteps = funnel?.steps?.length ? funnel.steps : initialStepsData;
|
|
const [steps, setSteps] = useState<FunnelStepData[]>(initialSteps);
|
|
const [hasIncompleteStepFields, setHasIncompleteStepFields] = useState(
|
|
steps.some((step) => step.service_name === '' || step.span_name === ''),
|
|
);
|
|
const [hasAllEmptyStepFields, setHasAllEmptyStepFields] = useState(
|
|
steps.every((step) => step.service_name === '' && step.span_name === ''),
|
|
);
|
|
const {
|
|
data: validationResponse,
|
|
isLoading: isValidationLoading,
|
|
isFetching: isValidationFetching,
|
|
} = useValidateFunnelSteps({
|
|
funnelId,
|
|
selectedTime,
|
|
startTime,
|
|
endTime,
|
|
});
|
|
|
|
const validTracesCount = useMemo(
|
|
() => validationResponse?.payload?.data?.length || 0,
|
|
[validationResponse],
|
|
);
|
|
|
|
// Step modifications
|
|
const handleStepUpdate = useCallback(
|
|
(index: number, newStep: Partial<FunnelStepData>) => {
|
|
setSteps((prev) =>
|
|
prev.map((step, i) => (i === index ? { ...step, ...newStep } : step)),
|
|
);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const addNewStep = useCallback(() => {
|
|
if (steps.length >= 3) return false;
|
|
|
|
setSteps((prev) => [
|
|
...prev,
|
|
{
|
|
...initialStepsData[0],
|
|
id: v4(),
|
|
step_order: prev.length + 1,
|
|
},
|
|
]);
|
|
return true;
|
|
}, [steps.length]);
|
|
|
|
const handleStepRemoval = useCallback((index: number) => {
|
|
setSteps((prev) =>
|
|
prev
|
|
// remove the step in the index
|
|
.filter((_, i) => i !== index)
|
|
// reset the step_order for the remaining steps
|
|
.map((step, newIndex) => ({
|
|
...step,
|
|
step_order: newIndex + 1,
|
|
})),
|
|
);
|
|
}, []);
|
|
|
|
const handleRestoreSteps = useCallback((oldSteps: FunnelStepData[]) => {
|
|
setSteps(oldSteps);
|
|
}, []);
|
|
|
|
const handleReplaceStep = useCallback(
|
|
(index: number, serviceName: string, spanName: string) => {
|
|
handleStepUpdate(index, {
|
|
service_name: serviceName,
|
|
span_name: spanName,
|
|
});
|
|
},
|
|
[handleStepUpdate],
|
|
);
|
|
if (!funnelId) {
|
|
throw new Error('Funnel ID is required');
|
|
}
|
|
|
|
const handleRunFunnel = useCallback(async (): Promise<void> => {
|
|
if (validTracesCount === 0) return;
|
|
queryClient.refetchQueries([
|
|
REACT_QUERY_KEY.GET_FUNNEL_OVERVIEW,
|
|
funnelId,
|
|
selectedTime,
|
|
]);
|
|
queryClient.refetchQueries([
|
|
REACT_QUERY_KEY.GET_FUNNEL_STEPS_GRAPH_DATA,
|
|
funnelId,
|
|
selectedTime,
|
|
]);
|
|
queryClient.refetchQueries([
|
|
REACT_QUERY_KEY.GET_FUNNEL_ERROR_TRACES,
|
|
funnelId,
|
|
selectedTime,
|
|
]);
|
|
queryClient.refetchQueries([
|
|
REACT_QUERY_KEY.GET_FUNNEL_SLOW_TRACES,
|
|
funnelId,
|
|
selectedTime,
|
|
]);
|
|
}, [funnelId, queryClient, selectedTime, validTracesCount]);
|
|
|
|
const value = useMemo<FunnelContextType>(
|
|
() => ({
|
|
funnelId,
|
|
startTime,
|
|
endTime,
|
|
validTracesCount,
|
|
selectedTime,
|
|
steps,
|
|
setSteps,
|
|
initialSteps,
|
|
handleStepChange: handleStepUpdate,
|
|
handleAddStep: addNewStep,
|
|
handleStepRemoval,
|
|
handleRunFunnel,
|
|
validationResponse,
|
|
isValidateStepsLoading: isValidationLoading || isValidationFetching,
|
|
hasIncompleteStepFields,
|
|
setHasIncompleteStepFields,
|
|
hasAllEmptyStepFields,
|
|
setHasAllEmptyStepFields,
|
|
handleReplaceStep,
|
|
handleRestoreSteps,
|
|
}),
|
|
[
|
|
funnelId,
|
|
startTime,
|
|
endTime,
|
|
validTracesCount,
|
|
selectedTime,
|
|
steps,
|
|
initialSteps,
|
|
handleStepUpdate,
|
|
addNewStep,
|
|
handleStepRemoval,
|
|
handleRunFunnel,
|
|
validationResponse,
|
|
isValidationLoading,
|
|
isValidationFetching,
|
|
hasIncompleteStepFields,
|
|
setHasIncompleteStepFields,
|
|
hasAllEmptyStepFields,
|
|
setHasAllEmptyStepFields,
|
|
handleReplaceStep,
|
|
handleRestoreSteps,
|
|
],
|
|
);
|
|
|
|
return (
|
|
<FunnelContext.Provider value={value}>{children}</FunnelContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useFunnelContext(): FunnelContextType {
|
|
const context = useContext(FunnelContext);
|
|
if (context === undefined) {
|
|
throw new Error('useFunnelContext must be used within a FunnelProvider');
|
|
}
|
|
return context;
|
|
}
|