Skip to content

Commit 6334e09

Browse files
ahmadshaheerYounixMshivanshuraj1333
authored
feat: Funnel Details Page Base Structure (#7364)
* 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 <[email protected]> * chore: remove console.og Signed-off-by: Shivanshu Raj Shrivastava <[email protected]> * chore: revert explicitly passing funnelId to updateFunnelSteps --------- Signed-off-by: Shivanshu Raj Shrivastava <[email protected]> Co-authored-by: ahmadshaheer <[email protected]> * chore: fix api endpoint Signed-off-by: Shivanshu Raj Shrivastava <[email protected]> * 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 <[email protected]> Co-authored-by: Yunus M <[email protected]> Co-authored-by: Shivanshu Raj Shrivastava <[email protected]>
1 parent 1d37993 commit 6334e09

File tree

89 files changed

+5665
-155
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+5665
-155
lines changed

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"less": "^4.1.2",
8888
"less-loader": "^10.2.0",
8989
"lodash-es": "^4.17.21",
90-
"lucide-react": "0.427.0",
90+
"lucide-react": "0.498.0",
9191
"mini-css-extract-plugin": "2.4.5",
9292
"motion": "12.4.13",
9393
"overlayscrollbars": "^2.8.1",
Lines changed: 2 additions & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

frontend/src/AppRoutes/pageComponents.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ export const TracesFunnels = Loadable(
4747
import(/* webpackChunkName: "Traces Funnels" */ 'pages/TracesModulePage'),
4848
);
4949
export const TracesFunnelDetails = Loadable(
50+
// eslint-disable-next-line sonarjs/no-identical-functions
5051
() =>
5152
import(
52-
/* webpackChunkName: "Traces Funnel Details" */ 'pages/TracesFunnelDetails'
53+
/* webpackChunkName: "Traces Funnel Details" */ 'pages/TracesModulePage'
5354
),
5455
);
5556

frontend/src/api/traceFunnels/index.ts

Lines changed: 258 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
CreateFunnelPayload,
66
CreateFunnelResponse,
77
FunnelData,
8+
FunnelStepData,
89
} from 'types/api/traceFunnels';
910

1011
const FUNNELS_BASE_PATH = '/trace-funnels';
@@ -13,7 +14,7 @@ export const createFunnel = async (
1314
payload: CreateFunnelPayload,
1415
): Promise<SuccessResponse<CreateFunnelResponse> | ErrorResponse> => {
1516
const response: AxiosResponse = await axios.post(
16-
`${FUNNELS_BASE_PATH}/new-funnel`,
17+
`${FUNNELS_BASE_PATH}/new`,
1718
payload,
1819
);
1920

@@ -25,60 +26,45 @@ export const createFunnel = async (
2526
};
2627
};
2728

28-
interface GetFunnelsListParams {
29-
search?: string;
30-
}
31-
32-
export const getFunnelsList = async ({
33-
search = '',
34-
}: GetFunnelsListParams = {}): Promise<
29+
export const getFunnelsList = async (): Promise<
3530
SuccessResponse<FunnelData[]> | ErrorResponse
3631
> => {
37-
const params = new URLSearchParams();
38-
if (search.length) {
39-
params.set('search', search);
40-
}
41-
42-
const response: AxiosResponse = await axios.get(
43-
`${FUNNELS_BASE_PATH}/list${
44-
params.toString() ? `?${params.toString()}` : ''
45-
}`,
46-
);
32+
const response: AxiosResponse = await axios.get(`${FUNNELS_BASE_PATH}/list`);
4733

4834
return {
4935
statusCode: 200,
5036
error: null,
5137
message: '',
52-
payload: response.data,
38+
payload: response.data.data,
5339
};
5440
};
5541

5642
export const getFunnelById = async (
57-
funnelId: string,
43+
funnelId?: string,
5844
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
5945
const response: AxiosResponse = await axios.get(
60-
`${FUNNELS_BASE_PATH}/get/${funnelId}`,
46+
`${FUNNELS_BASE_PATH}/${funnelId}`,
6147
);
62-
6348
return {
6449
statusCode: 200,
6550
error: null,
6651
message: '',
67-
payload: response.data,
52+
payload: response.data.data,
6853
};
6954
};
7055

71-
interface RenameFunnelPayload {
72-
id: string;
56+
export interface RenameFunnelPayload {
57+
funnel_id: string;
7358
funnel_name: string;
59+
timestamp: number;
7460
}
7561

7662
export const renameFunnel = async (
7763
payload: RenameFunnelPayload,
7864
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
7965
const response: AxiosResponse = await axios.put(
80-
`${FUNNELS_BASE_PATH}/${payload.id}/update`,
81-
{ funnel_name: payload.funnel_name },
66+
`${FUNNELS_BASE_PATH}/${payload.funnel_id}`,
67+
payload,
8268
);
8369

8470
return {
@@ -97,7 +83,7 @@ export const deleteFunnel = async (
9783
payload: DeleteFunnelPayload,
9884
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
9985
const response: AxiosResponse = await axios.delete(
100-
`${FUNNELS_BASE_PATH}/delete/${payload.id}`,
86+
`${FUNNELS_BASE_PATH}/${payload.id}`,
10187
);
10288

10389
return {
@@ -107,3 +93,247 @@ export const deleteFunnel = async (
10793
payload: response.data,
10894
};
10995
};
96+
97+
export interface UpdateFunnelStepsPayload {
98+
funnel_id: string;
99+
steps: FunnelStepData[];
100+
timestamp: number;
101+
}
102+
103+
export const updateFunnelSteps = async (
104+
payload: UpdateFunnelStepsPayload,
105+
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
106+
const response: AxiosResponse = await axios.put(
107+
`${FUNNELS_BASE_PATH}/steps/update`,
108+
payload,
109+
);
110+
111+
return {
112+
statusCode: 200,
113+
error: null,
114+
message: 'Funnel steps updated successfully',
115+
payload: response.data.data,
116+
};
117+
};
118+
119+
export interface ValidateFunnelPayload {
120+
start_time: number;
121+
end_time: number;
122+
}
123+
124+
export interface ValidateFunnelResponse {
125+
status: string;
126+
data: Array<{
127+
timestamp: string;
128+
data: {
129+
trace_id: string;
130+
};
131+
}> | null;
132+
}
133+
134+
export const validateFunnelSteps = async (
135+
funnelId: string,
136+
payload: ValidateFunnelPayload,
137+
signal?: AbortSignal,
138+
): Promise<SuccessResponse<ValidateFunnelResponse> | ErrorResponse> => {
139+
const response = await axios.post(
140+
`${FUNNELS_BASE_PATH}/${funnelId}/analytics/validate`,
141+
payload,
142+
{ signal },
143+
);
144+
145+
return {
146+
statusCode: 200,
147+
error: null,
148+
message: '',
149+
payload: response.data,
150+
};
151+
};
152+
153+
export interface UpdateFunnelStepDetailsPayload {
154+
funnel_id: string;
155+
steps: Array<{
156+
step_name: string;
157+
description: string;
158+
}>;
159+
updated_at: number;
160+
}
161+
162+
interface UpdateFunnelDescriptionPayload {
163+
funnel_id: string;
164+
description: string;
165+
}
166+
167+
export const saveFunnelDescription = async (
168+
payload: UpdateFunnelDescriptionPayload,
169+
): Promise<SuccessResponse<FunnelData> | ErrorResponse> => {
170+
const response: AxiosResponse = await axios.post(
171+
`${FUNNELS_BASE_PATH}/save`,
172+
payload,
173+
);
174+
175+
return {
176+
statusCode: 200,
177+
error: null,
178+
message: 'Funnel description updated successfully',
179+
payload: response.data,
180+
};
181+
};
182+
183+
export interface FunnelOverviewPayload {
184+
start_time: number;
185+
end_time: number;
186+
step_start?: number;
187+
step_end?: number;
188+
}
189+
190+
export interface FunnelOverviewResponse {
191+
status: string;
192+
data: Array<{
193+
timestamp: string;
194+
data: {
195+
avg_duration: number;
196+
avg_rate: number;
197+
conversion_rate: number | null;
198+
errors: number;
199+
p99_latency: number;
200+
};
201+
}>;
202+
}
203+
204+
export const getFunnelOverview = async (
205+
funnelId: string,
206+
payload: FunnelOverviewPayload,
207+
signal?: AbortSignal,
208+
): Promise<SuccessResponse<FunnelOverviewResponse> | ErrorResponse> => {
209+
const response = await axios.post(
210+
`${FUNNELS_BASE_PATH}/${funnelId}/analytics/overview`,
211+
payload,
212+
{
213+
signal,
214+
},
215+
);
216+
217+
return {
218+
statusCode: 200,
219+
error: null,
220+
message: '',
221+
payload: response.data,
222+
};
223+
};
224+
225+
export interface SlowTracesPayload {
226+
start_time: number;
227+
end_time: number;
228+
step_a_order: number;
229+
step_b_order: number;
230+
}
231+
232+
export interface SlowTraceData {
233+
status: string;
234+
data: Array<{
235+
timestamp: string;
236+
data: {
237+
duration_ms: string;
238+
span_count: number;
239+
trace_id: string;
240+
};
241+
}>;
242+
}
243+
244+
export const getFunnelSlowTraces = async (
245+
funnelId: string,
246+
payload: SlowTracesPayload,
247+
signal?: AbortSignal,
248+
): Promise<SuccessResponse<SlowTraceData> | ErrorResponse> => {
249+
const response = await axios.post(
250+
`${FUNNELS_BASE_PATH}/${funnelId}/analytics/slow-traces`,
251+
payload,
252+
{
253+
signal,
254+
},
255+
);
256+
257+
return {
258+
statusCode: 200,
259+
error: null,
260+
message: '',
261+
payload: response.data,
262+
};
263+
};
264+
export interface ErrorTracesPayload {
265+
start_time: number;
266+
end_time: number;
267+
step_a_order: number;
268+
step_b_order: number;
269+
}
270+
271+
export interface ErrorTraceData {
272+
status: string;
273+
data: Array<{
274+
timestamp: string;
275+
data: {
276+
duration_ms: string;
277+
span_count: number;
278+
trace_id: string;
279+
};
280+
}>;
281+
}
282+
283+
export const getFunnelErrorTraces = async (
284+
funnelId: string,
285+
payload: ErrorTracesPayload,
286+
signal?: AbortSignal,
287+
): Promise<SuccessResponse<ErrorTraceData> | ErrorResponse> => {
288+
const response: AxiosResponse = await axios.post(
289+
`${FUNNELS_BASE_PATH}/${funnelId}/analytics/error-traces`,
290+
payload,
291+
{
292+
signal,
293+
},
294+
);
295+
296+
return {
297+
statusCode: 200,
298+
error: null,
299+
message: '',
300+
payload: response.data,
301+
};
302+
};
303+
304+
export interface FunnelStepsPayload {
305+
start_time: number;
306+
end_time: number;
307+
}
308+
309+
export interface FunnelStepGraphMetrics {
310+
[key: `total_s${number}_spans`]: number;
311+
[key: `total_s${number}_errored_spans`]: number;
312+
}
313+
314+
export interface FunnelStepsResponse {
315+
status: string;
316+
data: Array<{
317+
timestamp: string;
318+
data: FunnelStepGraphMetrics;
319+
}>;
320+
}
321+
322+
export const getFunnelSteps = async (
323+
funnelId: string,
324+
payload: FunnelStepsPayload,
325+
signal?: AbortSignal,
326+
): Promise<SuccessResponse<FunnelStepsResponse> | ErrorResponse> => {
327+
const response = await axios.post(
328+
`${FUNNELS_BASE_PATH}/${funnelId}/analytics/steps`,
329+
payload,
330+
{ signal },
331+
);
332+
333+
return {
334+
statusCode: 200,
335+
error: null,
336+
message: '',
337+
payload: response.data,
338+
};
339+
};

0 commit comments

Comments
 (0)