rusty-replay 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +10 -0
- package/.vscode/settings.json +3 -0
- package/README.md +92 -0
- package/apps/web/README.md +11 -0
- package/apps/web/api/auth/keys.ts +3 -0
- package/apps/web/api/auth/types.ts +25 -0
- package/apps/web/api/auth/use-query-profile.ts +19 -0
- package/apps/web/api/auth/use-sign-in.ts +24 -0
- package/apps/web/api/axios.ts +122 -0
- package/apps/web/api/error-code.ts +36 -0
- package/apps/web/api/event/keys.ts +14 -0
- package/apps/web/api/event/types.ts +91 -0
- package/apps/web/api/event/use-mutation-event-assignee.ts +103 -0
- package/apps/web/api/event/use-mutation-event-priority.ts +97 -0
- package/apps/web/api/event/use-mutation-event-status.ts +198 -0
- package/apps/web/api/event/use-query-event-detail.ts +25 -0
- package/apps/web/api/event/use-query-event-list.ts +42 -0
- package/apps/web/api/health-check/index.ts +21 -0
- package/apps/web/api/project/keys.ts +4 -0
- package/apps/web/api/project/types.ts +28 -0
- package/apps/web/api/project/use-create-project.ts +30 -0
- package/apps/web/api/project/use-query-project-list.ts +19 -0
- package/apps/web/api/project/use-query-project-users.ts +23 -0
- package/apps/web/api/types.ts +44 -0
- package/apps/web/app/(auth)/layout.tsx +5 -0
- package/apps/web/app/(auth)/sign-in/page.tsx +20 -0
- package/apps/web/app/(auth)/sign-up/page.tsx +5 -0
- package/apps/web/app/(project)/project/[project_id]/issues/[issue_id]/page.tsx +17 -0
- package/apps/web/app/(project)/project/[project_id]/issues/page.tsx +15 -0
- package/apps/web/app/(project)/project/[project_id]/page.tsx +10 -0
- package/apps/web/app/(project)/project/page.tsx +10 -0
- package/apps/web/app/(report)/error-list/page.tsx +7 -0
- package/apps/web/app/favicon.ico +0 -0
- package/apps/web/app/layout.tsx +35 -0
- package/apps/web/app/page.tsx +3 -0
- package/apps/web/components/.gitkeep +0 -0
- package/apps/web/components/event-list/event-detail.tsx +242 -0
- package/apps/web/components/event-list/event-list.tsx +376 -0
- package/apps/web/components/event-list/preview.tsx +573 -0
- package/apps/web/components/layouts/default-layout.tsx +59 -0
- package/apps/web/components/login-form.tsx +124 -0
- package/apps/web/components/project/create-project.tsx +130 -0
- package/apps/web/components/project/hooks/use-get-event-params.ts +9 -0
- package/apps/web/components/project/hooks/use-get-project-params.ts +10 -0
- package/apps/web/components/project/project-detail.tsx +240 -0
- package/apps/web/components/project/project-list.tsx +137 -0
- package/apps/web/components/providers.tsx +25 -0
- package/apps/web/components/ui/assignee-dropdown.tsx +176 -0
- package/apps/web/components/ui/event-status-dropdown.tsx +104 -0
- package/apps/web/components/ui/priority-dropdown.tsx +123 -0
- package/apps/web/components/widget/app-sidebar.tsx +225 -0
- package/apps/web/components/widget/nav-main.tsx +73 -0
- package/apps/web/components/widget/nav-projects.tsx +84 -0
- package/apps/web/components/widget/nav-user.tsx +113 -0
- package/apps/web/components.json +20 -0
- package/apps/web/constants/routes.ts +12 -0
- package/apps/web/eslint.config.js +4 -0
- package/apps/web/hooks/use-boolean-state.ts +13 -0
- package/apps/web/lib/.gitkeep +0 -0
- package/apps/web/next-env.d.ts +5 -0
- package/apps/web/next.config.mjs +6 -0
- package/apps/web/package.json +60 -0
- package/apps/web/postcss.config.mjs +1 -0
- package/apps/web/providers/flag-provider.tsx +35 -0
- package/apps/web/providers/query-client-provider.tsx +17 -0
- package/apps/web/providers/telemetry-provider.tsx +12 -0
- package/apps/web/tsconfig.json +24 -0
- package/apps/web/utils/avatar.ts +26 -0
- package/apps/web/utils/date.ts +26 -0
- package/apps/web/utils/front-end-tracer.ts +119 -0
- package/apps/web/utils/schema/project.schema.ts +12 -0
- package/apps/web/utils/span-processor.ts +36 -0
- package/package.json +21 -0
- package/packages/eslint-config/README.md +3 -0
- package/packages/eslint-config/base.js +32 -0
- package/packages/eslint-config/next.js +51 -0
- package/packages/eslint-config/package.json +25 -0
- package/packages/eslint-config/react-internal.js +41 -0
- package/packages/rusty-replay/README.md +165 -0
- package/packages/rusty-replay/package.json +67 -0
- package/packages/rusty-replay/src/environment.ts +27 -0
- package/packages/rusty-replay/src/error-batcher.ts +75 -0
- package/packages/rusty-replay/src/front-end-tracer.ts +86 -0
- package/packages/rusty-replay/src/handler.ts +37 -0
- package/packages/rusty-replay/src/index.ts +8 -0
- package/packages/rusty-replay/src/recorder.ts +71 -0
- package/packages/rusty-replay/src/reporter.ts +115 -0
- package/packages/rusty-replay/src/utils.ts +13 -0
- package/packages/rusty-replay/tsconfig.build.json +13 -0
- package/packages/rusty-replay/tsconfig.json +27 -0
- package/packages/rusty-replay/tsup.config.ts +39 -0
- package/packages/typescript-config/README.md +3 -0
- package/packages/typescript-config/base.json +20 -0
- package/packages/typescript-config/nextjs.json +13 -0
- package/packages/typescript-config/package.json +9 -0
- package/packages/typescript-config/react-library.json +8 -0
- package/packages/ui/components.json +20 -0
- package/packages/ui/eslint.config.js +4 -0
- package/packages/ui/package.json +60 -0
- package/packages/ui/postcss.config.mjs +6 -0
- package/packages/ui/src/components/.gitkeep +0 -0
- package/packages/ui/src/components/avatar.tsx +53 -0
- package/packages/ui/src/components/badge.tsx +46 -0
- package/packages/ui/src/components/breadcrumb.tsx +109 -0
- package/packages/ui/src/components/button.tsx +59 -0
- package/packages/ui/src/components/calendar.tsx +75 -0
- package/packages/ui/src/components/calendars/date-picker.tsx +43 -0
- package/packages/ui/src/components/calendars/date-range-picker.tsx +79 -0
- package/packages/ui/src/components/card.tsx +92 -0
- package/packages/ui/src/components/checkbox.tsx +32 -0
- package/packages/ui/src/components/collapsible.tsx +33 -0
- package/packages/ui/src/components/dialog.tsx +135 -0
- package/packages/ui/src/components/dialogs/confirmation-modal.tsx +216 -0
- package/packages/ui/src/components/dropdown-menu.tsx +261 -0
- package/packages/ui/src/components/input.tsx +30 -0
- package/packages/ui/src/components/label.tsx +24 -0
- package/packages/ui/src/components/login-form.tsx +68 -0
- package/packages/ui/src/components/mode-switcher.tsx +34 -0
- package/packages/ui/src/components/popover.tsx +48 -0
- package/packages/ui/src/components/scroll-area.tsx +58 -0
- package/packages/ui/src/components/select.tsx +185 -0
- package/packages/ui/src/components/separator.tsx +28 -0
- package/packages/ui/src/components/sheet.tsx +139 -0
- package/packages/ui/src/components/sidebar.tsx +726 -0
- package/packages/ui/src/components/skeleton.tsx +13 -0
- package/packages/ui/src/components/sonner.tsx +25 -0
- package/packages/ui/src/components/table.tsx +116 -0
- package/packages/ui/src/components/tabs.tsx +66 -0
- package/packages/ui/src/components/team-switcher.tsx +91 -0
- package/packages/ui/src/components/textarea.tsx +18 -0
- package/packages/ui/src/components/tooltip.tsx +61 -0
- package/packages/ui/src/hooks/.gitkeep +0 -0
- package/packages/ui/src/hooks/use-meta-color.ts +28 -0
- package/packages/ui/src/hooks/use-mobile.ts +19 -0
- package/packages/ui/src/lib/utils.ts +6 -0
- package/packages/ui/src/styles/globals.css +138 -0
- package/packages/ui/tsconfig.json +13 -0
- package/packages/ui/tsconfig.lint.json +8 -0
- package/pnpm-workspace.yaml +4 -0
- package/tsconfig.json +4 -0
- package/turbo.json +21 -0
@@ -0,0 +1,198 @@
|
|
1
|
+
import {
|
2
|
+
useMutation,
|
3
|
+
UseMutationOptions,
|
4
|
+
useQueryClient,
|
5
|
+
} from '@tanstack/react-query';
|
6
|
+
import { ResponseError } from '../types';
|
7
|
+
import {
|
8
|
+
EventReportListContext,
|
9
|
+
EventReportListResponse,
|
10
|
+
EventReportResponse,
|
11
|
+
EventStatus,
|
12
|
+
} from './types';
|
13
|
+
import axiosInstance from '../axios';
|
14
|
+
import { eventKeys } from './keys';
|
15
|
+
import { PaginatedResponse } from '../types';
|
16
|
+
|
17
|
+
export function useMutationEventStatus({
|
18
|
+
projectId,
|
19
|
+
options,
|
20
|
+
}: {
|
21
|
+
projectId: number;
|
22
|
+
options?: UseMutationOptions<
|
23
|
+
EventReportListResponse[],
|
24
|
+
ResponseError,
|
25
|
+
EventStatus,
|
26
|
+
EventReportListContext
|
27
|
+
>;
|
28
|
+
}) {
|
29
|
+
const queryClient = useQueryClient();
|
30
|
+
const listQueryKey = eventKeys.list(projectId);
|
31
|
+
const mutationFn = (data: EventStatus) =>
|
32
|
+
axiosInstance
|
33
|
+
.put(eventKeys.status(projectId), data)
|
34
|
+
.then((res) => res.data);
|
35
|
+
|
36
|
+
return useMutation({
|
37
|
+
mutationKey: [eventKeys.status(projectId)],
|
38
|
+
mutationFn,
|
39
|
+
onMutate: async (newData) => {
|
40
|
+
const { eventIds, status } = newData;
|
41
|
+
|
42
|
+
await queryClient.cancelQueries({ queryKey: [listQueryKey] });
|
43
|
+
|
44
|
+
const previousQueries = queryClient.getQueriesData<
|
45
|
+
PaginatedResponse<EventReportListResponse>
|
46
|
+
>({
|
47
|
+
queryKey: [listQueryKey],
|
48
|
+
});
|
49
|
+
|
50
|
+
const previousDetailQueries: Record<
|
51
|
+
number,
|
52
|
+
EventReportResponse | undefined
|
53
|
+
> = {};
|
54
|
+
eventIds.forEach((id) => {
|
55
|
+
const key = [`/api/projects/${projectId}/events/${id}`];
|
56
|
+
previousDetailQueries[id] =
|
57
|
+
queryClient.getQueryData<EventReportResponse>(key);
|
58
|
+
});
|
59
|
+
|
60
|
+
queryClient.setQueriesData<PaginatedResponse<EventReportListResponse>>(
|
61
|
+
{ queryKey: [listQueryKey] },
|
62
|
+
(old) => {
|
63
|
+
if (!old) return old;
|
64
|
+
return {
|
65
|
+
...old,
|
66
|
+
content: old.content.map((evt) =>
|
67
|
+
eventIds.includes(evt.id) ? { ...evt, status } : evt
|
68
|
+
),
|
69
|
+
};
|
70
|
+
}
|
71
|
+
);
|
72
|
+
|
73
|
+
eventIds.forEach((id) => {
|
74
|
+
const detailKey = [eventKeys.detail(projectId, id)];
|
75
|
+
queryClient.setQueryData<EventReportResponse>(detailKey, (old) => {
|
76
|
+
if (!old) return old;
|
77
|
+
return { ...old, status };
|
78
|
+
});
|
79
|
+
});
|
80
|
+
|
81
|
+
return { previousQueries, previousDetailQueries };
|
82
|
+
},
|
83
|
+
onError: (err, newData, context) => {
|
84
|
+
context?.previousQueries.forEach(([key, data]) => {
|
85
|
+
queryClient.setQueryData(key, data);
|
86
|
+
});
|
87
|
+
if (context?.previousDetailQueries) {
|
88
|
+
Object.entries(context.previousDetailQueries).forEach(([id, data]) => {
|
89
|
+
const detailKey = [`/api/projects/${projectId}/events/${id}`];
|
90
|
+
queryClient.setQueryData(detailKey, data);
|
91
|
+
});
|
92
|
+
}
|
93
|
+
},
|
94
|
+
...options,
|
95
|
+
});
|
96
|
+
}
|
97
|
+
|
98
|
+
// import {
|
99
|
+
// useMutation,
|
100
|
+
// UseMutationOptions,
|
101
|
+
// useQueryClient,
|
102
|
+
// } from '@tanstack/react-query';
|
103
|
+
// import {
|
104
|
+
// EventReportListResponse,
|
105
|
+
// EventReportResponse,
|
106
|
+
// EventStatus,
|
107
|
+
// EventStatusContext,
|
108
|
+
// } from './types';
|
109
|
+
// import { PaginatedResponse, ResponseError } from '../types';
|
110
|
+
// import { eventKeys } from './keys';
|
111
|
+
// import axiosInstance from '../axios';
|
112
|
+
// import { toast } from '@workspace/ui/components/sonner';
|
113
|
+
|
114
|
+
// export function useMutationEventStatus({
|
115
|
+
// projectId,
|
116
|
+
// options,
|
117
|
+
// }: {
|
118
|
+
// projectId: number;
|
119
|
+
// options?: UseMutationOptions<
|
120
|
+
// EventReportListResponse[],
|
121
|
+
// ResponseError,
|
122
|
+
// EventStatus,
|
123
|
+
// EventStatusContext
|
124
|
+
// >;
|
125
|
+
// }) {
|
126
|
+
// const queryClient = useQueryClient();
|
127
|
+
// const queryKey = eventKeys.list(projectId);
|
128
|
+
// // const detailQueryKey = `/api/projects/${projectId}/events/${eventId}`;
|
129
|
+
// const mutationKey = eventKeys.status(projectId);
|
130
|
+
// const mutationFn = (data: EventStatus) =>
|
131
|
+
// axiosInstance.put(mutationKey, data).then((res) => res.data);
|
132
|
+
|
133
|
+
// return useMutation({
|
134
|
+
// mutationKey: [mutationKey],
|
135
|
+
// mutationFn,
|
136
|
+
// onMutate: async (newStatus) => {
|
137
|
+
// await queryClient.cancelQueries({
|
138
|
+
// queryKey: [queryKey],
|
139
|
+
// });
|
140
|
+
// await queryClient.cancelQueries({
|
141
|
+
// queryKey: [detailQueryKey],
|
142
|
+
// });
|
143
|
+
|
144
|
+
// const previousQueries = queryClient.getQueriesData<
|
145
|
+
// PaginatedResponse<EventReportListResponse>
|
146
|
+
// >({
|
147
|
+
// queryKey: [queryKey],
|
148
|
+
// });
|
149
|
+
|
150
|
+
// const previousDetailQuery = queryClient.getQueryData<EventReportResponse>(
|
151
|
+
// [detailQueryKey]
|
152
|
+
// );
|
153
|
+
|
154
|
+
// queryClient.setQueriesData<PaginatedResponse<EventReportListResponse>>(
|
155
|
+
// {
|
156
|
+
// queryKey: [queryKey],
|
157
|
+
// },
|
158
|
+
// (old) => {
|
159
|
+
// if (!old) return old;
|
160
|
+
|
161
|
+
// return {
|
162
|
+
// ...old,
|
163
|
+
// content: old.content.map((event) =>
|
164
|
+
// event.id === eventId
|
165
|
+
// ? { ...event, status: newStatus.status }
|
166
|
+
// : event
|
167
|
+
// ),
|
168
|
+
// };
|
169
|
+
// }
|
170
|
+
// );
|
171
|
+
|
172
|
+
// queryClient.setQueryData<EventReportResponse>([detailQueryKey], (old) => {
|
173
|
+
// if (!old) return old;
|
174
|
+
// return {
|
175
|
+
// ...old,
|
176
|
+
// status: newStatus.status,
|
177
|
+
// };
|
178
|
+
// });
|
179
|
+
|
180
|
+
// return { previousQueries, previousDetailQuery };
|
181
|
+
// },
|
182
|
+
// onError: (err, newStatus, context) => {
|
183
|
+
// if (context?.previousQueries) {
|
184
|
+
// context.previousQueries.forEach(([queryKey, data]) => {
|
185
|
+
// queryClient.setQueryData(queryKey, data);
|
186
|
+
// });
|
187
|
+
// }
|
188
|
+
|
189
|
+
// if (context?.previousDetailQuery) {
|
190
|
+
// queryClient.setQueryData([detailQueryKey], context.previousDetailQuery);
|
191
|
+
// }
|
192
|
+
|
193
|
+
// console.error(err);
|
194
|
+
// toast.error('Failed to update status');
|
195
|
+
// },
|
196
|
+
// ...options,
|
197
|
+
// });
|
198
|
+
// }
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
2
|
+
import { UseQueryCustomOptions } from '../types';
|
3
|
+
import { EventReportResponse } from './types';
|
4
|
+
import axiosInstance from '../axios';
|
5
|
+
import { eventKeys } from './keys';
|
6
|
+
|
7
|
+
export function useQueryEventDetail({
|
8
|
+
projectId,
|
9
|
+
eventId,
|
10
|
+
options,
|
11
|
+
}: {
|
12
|
+
projectId: number;
|
13
|
+
eventId: number;
|
14
|
+
options?: UseQueryCustomOptions<void, EventReportResponse>;
|
15
|
+
}) {
|
16
|
+
const queryKey = eventKeys.detail(projectId, eventId);
|
17
|
+
const queryFn = async () =>
|
18
|
+
await axiosInstance.get(queryKey).then((res) => res.data);
|
19
|
+
|
20
|
+
return useQuery({
|
21
|
+
queryKey: [queryKey],
|
22
|
+
queryFn,
|
23
|
+
...options,
|
24
|
+
});
|
25
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
2
|
+
import { PaginatedResponse, UseQueryCustomOptions } from '../types';
|
3
|
+
import { EventQuery, EventReportListResponse } from './types';
|
4
|
+
import axiosInstance from '../axios';
|
5
|
+
import { eventKeys } from './keys';
|
6
|
+
|
7
|
+
export function useQueryErrorList({
|
8
|
+
projectId,
|
9
|
+
eventQuery,
|
10
|
+
options,
|
11
|
+
}: {
|
12
|
+
projectId: number;
|
13
|
+
eventQuery: EventQuery;
|
14
|
+
options?: UseQueryCustomOptions<
|
15
|
+
void,
|
16
|
+
PaginatedResponse<EventReportListResponse>
|
17
|
+
>;
|
18
|
+
}) {
|
19
|
+
const queryParams = new URLSearchParams();
|
20
|
+
|
21
|
+
if (eventQuery.search) queryParams.append('search', eventQuery.search);
|
22
|
+
if (eventQuery.page) queryParams.append('page', String(eventQuery.page));
|
23
|
+
if (eventQuery.pageSize)
|
24
|
+
queryParams.append('pageSize', String(eventQuery.pageSize));
|
25
|
+
if (eventQuery.startDate)
|
26
|
+
queryParams.append('startDate', eventQuery.startDate);
|
27
|
+
if (eventQuery.endDate) queryParams.append('endDate', eventQuery.endDate);
|
28
|
+
|
29
|
+
// const fullUrl = `/api/projects/${projectId}/events${queryString ? `?${queryString}` : ''}`;
|
30
|
+
const fullUrl = eventKeys.list(projectId, queryParams);
|
31
|
+
|
32
|
+
const queryKey = [eventKeys.list(projectId), eventQuery];
|
33
|
+
|
34
|
+
const queryFn = async () =>
|
35
|
+
axiosInstance.get(fullUrl).then((res) => res.data);
|
36
|
+
|
37
|
+
return useQuery({
|
38
|
+
queryKey,
|
39
|
+
queryFn,
|
40
|
+
...options,
|
41
|
+
});
|
42
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
2
|
+
import { UseMutationCustomOptions } from '../types';
|
3
|
+
import axiosInstance from '../axios';
|
4
|
+
|
5
|
+
export function healthCheck({
|
6
|
+
enabled = false,
|
7
|
+
options,
|
8
|
+
}: {
|
9
|
+
enabled: boolean;
|
10
|
+
options?: UseMutationCustomOptions<string, void>;
|
11
|
+
}) {
|
12
|
+
const queryKey = '/health-check';
|
13
|
+
|
14
|
+
return useQuery({
|
15
|
+
queryKey: [queryKey],
|
16
|
+
queryFn: async () =>
|
17
|
+
await axiosInstance.get(queryKey).then((res) => res.data),
|
18
|
+
enabled,
|
19
|
+
...options,
|
20
|
+
});
|
21
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { BaseTimeEntity } from '../types';
|
2
|
+
|
3
|
+
export interface Project extends BaseTimeEntity {
|
4
|
+
id: number;
|
5
|
+
name: string;
|
6
|
+
apiKey: string;
|
7
|
+
description: string;
|
8
|
+
}
|
9
|
+
|
10
|
+
export interface ProjectCreateRequest {
|
11
|
+
name: string;
|
12
|
+
description?: string | null;
|
13
|
+
}
|
14
|
+
|
15
|
+
export interface ProjectResponse extends BaseTimeEntity {
|
16
|
+
id: number;
|
17
|
+
name: string;
|
18
|
+
apiKey: string;
|
19
|
+
description: string | null;
|
20
|
+
}
|
21
|
+
|
22
|
+
export interface ProjectMemberResponse {
|
23
|
+
userId: number;
|
24
|
+
username: string;
|
25
|
+
email: string;
|
26
|
+
role: string;
|
27
|
+
jointedAt: string;
|
28
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
2
|
+
import axiosInstance from '../axios';
|
3
|
+
import { ProjectCreateRequest, ProjectResponse } from './types';
|
4
|
+
import { toast } from '@workspace/ui/components/sonner';
|
5
|
+
import { UseMutationCustomOptions } from '../types';
|
6
|
+
import { projectKeys } from './keys';
|
7
|
+
|
8
|
+
export function useCreateProject(
|
9
|
+
options?: UseMutationCustomOptions<ProjectResponse, ProjectCreateRequest>
|
10
|
+
) {
|
11
|
+
const queryClient = useQueryClient();
|
12
|
+
|
13
|
+
const mutationKey = `/api/projects`;
|
14
|
+
const mutationFn = async (data: ProjectCreateRequest) =>
|
15
|
+
await axiosInstance.post(mutationKey, data).then((res) => res.data);
|
16
|
+
|
17
|
+
return useMutation({
|
18
|
+
mutationKey: [mutationKey],
|
19
|
+
mutationFn,
|
20
|
+
onSuccess: (data) => {
|
21
|
+
queryClient.invalidateQueries({
|
22
|
+
queryKey: [projectKeys.list()],
|
23
|
+
});
|
24
|
+
},
|
25
|
+
onError: (error) => {
|
26
|
+
console.error(error);
|
27
|
+
},
|
28
|
+
...options,
|
29
|
+
});
|
30
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
2
|
+
import { UseQueryCustomOptions } from '../types';
|
3
|
+
import { Project } from './types';
|
4
|
+
import axiosInstance from '../axios';
|
5
|
+
import { projectKeys } from './keys';
|
6
|
+
|
7
|
+
export function useQueryProjectList(
|
8
|
+
options?: UseQueryCustomOptions<void, Project[]>
|
9
|
+
) {
|
10
|
+
const queryKey = projectKeys.list();
|
11
|
+
const queryFn = async () =>
|
12
|
+
await axiosInstance.get(queryKey).then((res) => res.data);
|
13
|
+
|
14
|
+
return useQuery({
|
15
|
+
queryKey: [queryKey],
|
16
|
+
queryFn,
|
17
|
+
...options,
|
18
|
+
});
|
19
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
2
|
+
import { projectKeys } from './keys';
|
3
|
+
import { UseQueryCustomOptions } from '../types';
|
4
|
+
import { ProjectMemberResponse } from './types';
|
5
|
+
import axiosInstance from '../axios';
|
6
|
+
|
7
|
+
export function useQueryProjectUsers({
|
8
|
+
projectId,
|
9
|
+
options,
|
10
|
+
}: {
|
11
|
+
projectId: number;
|
12
|
+
options?: UseQueryCustomOptions<void, ProjectMemberResponse[]>;
|
13
|
+
}) {
|
14
|
+
const queryKey = projectKeys.userList(projectId);
|
15
|
+
const queryFn = async () =>
|
16
|
+
await axiosInstance.get(queryKey).then((res) => res.data);
|
17
|
+
|
18
|
+
return useQuery({
|
19
|
+
queryKey: [queryKey],
|
20
|
+
queryFn,
|
21
|
+
...options,
|
22
|
+
});
|
23
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import {
|
2
|
+
QueryKey,
|
3
|
+
UseMutationOptions,
|
4
|
+
UseQueryOptions,
|
5
|
+
} from '@tanstack/react-query';
|
6
|
+
import { AxiosError } from 'axios';
|
7
|
+
import { ERROR_CODE } from './error-code';
|
8
|
+
|
9
|
+
type ResponseError = AxiosError<{
|
10
|
+
errorCode: keyof typeof ERROR_CODE;
|
11
|
+
message: string;
|
12
|
+
}>;
|
13
|
+
|
14
|
+
type UseMutationCustomOptions<TData = unknown, TVariables = unknown> = Omit<
|
15
|
+
UseMutationOptions<TData, ResponseError, TVariables, unknown>,
|
16
|
+
'mutationFn'
|
17
|
+
>;
|
18
|
+
type UseQueryCustomOptions<TQueryFnData = unknown, TData = TQueryFnData> = Omit<
|
19
|
+
UseQueryOptions<TQueryFnData, ResponseError, TData, QueryKey>,
|
20
|
+
'queryKey'
|
21
|
+
>;
|
22
|
+
|
23
|
+
interface BaseTimeEntity {
|
24
|
+
createdAt: string;
|
25
|
+
updatedAt: string | null;
|
26
|
+
}
|
27
|
+
|
28
|
+
interface PaginatedResponse<T> {
|
29
|
+
content: T[];
|
30
|
+
page: number;
|
31
|
+
pageSize: number;
|
32
|
+
totalElements: number;
|
33
|
+
filteredElements: number;
|
34
|
+
totalPages: number;
|
35
|
+
hasNext: boolean;
|
36
|
+
}
|
37
|
+
|
38
|
+
export type {
|
39
|
+
ResponseError,
|
40
|
+
UseMutationCustomOptions,
|
41
|
+
UseQueryCustomOptions,
|
42
|
+
BaseTimeEntity,
|
43
|
+
PaginatedResponse,
|
44
|
+
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { healthCheck } from '@/api/health-check';
|
4
|
+
import { LoginForm } from '@/components/login-form';
|
5
|
+
import { Button } from '@workspace/ui/components/button';
|
6
|
+
|
7
|
+
export default function SignInPage() {
|
8
|
+
const { data, refetch } = healthCheck({ enabled: false });
|
9
|
+
|
10
|
+
return (
|
11
|
+
<div className="flex min-h-svh w-full items-center justify-center p-6 md:p-10">
|
12
|
+
<div className="w-full max-w-sm">
|
13
|
+
<LoginForm />
|
14
|
+
<Button size={'sm'} onClick={() => refetch()}>
|
15
|
+
health check
|
16
|
+
</Button>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
);
|
20
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import EventDetail from '@/components/event-list/event-detail';
|
4
|
+
import { useGetEventParams } from '@/components/project/hooks/use-get-event-params';
|
5
|
+
import { useGetProjectParams } from '@/components/project/hooks/use-get-project-params';
|
6
|
+
import React from 'react';
|
7
|
+
|
8
|
+
export default function ErrorDetailPage() {
|
9
|
+
const { projectId } = useGetProjectParams();
|
10
|
+
const { eventId } = useGetEventParams();
|
11
|
+
|
12
|
+
return (
|
13
|
+
<div>
|
14
|
+
<EventDetail params={{ eventId, projectId }} />
|
15
|
+
</div>
|
16
|
+
);
|
17
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import EventList from '@/components/event-list/event-list';
|
4
|
+
import { useGetProjectParams } from '@/components/project/hooks/use-get-project-params';
|
5
|
+
import React from 'react';
|
6
|
+
|
7
|
+
export default function ErrorListPage() {
|
8
|
+
const { projectId } = useGetProjectParams();
|
9
|
+
|
10
|
+
return (
|
11
|
+
<div>
|
12
|
+
<EventList projectId={projectId} />
|
13
|
+
</div>
|
14
|
+
);
|
15
|
+
}
|
Binary file
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { Geist, Geist_Mono } from 'next/font/google';
|
2
|
+
|
3
|
+
import '@workspace/ui/globals.css';
|
4
|
+
import { Providers } from '@/components/providers';
|
5
|
+
import { Toaster } from '@workspace/ui/components/sonner';
|
6
|
+
import DefaultLayout from '@/components/layouts/default-layout';
|
7
|
+
|
8
|
+
const fontSans = Geist({
|
9
|
+
subsets: ['latin'],
|
10
|
+
variable: '--font-sans',
|
11
|
+
});
|
12
|
+
|
13
|
+
const fontMono = Geist_Mono({
|
14
|
+
subsets: ['latin'],
|
15
|
+
variable: '--font-mono',
|
16
|
+
});
|
17
|
+
|
18
|
+
export default function RootLayout({
|
19
|
+
children,
|
20
|
+
}: Readonly<{
|
21
|
+
children: React.ReactNode;
|
22
|
+
}>) {
|
23
|
+
return (
|
24
|
+
<html lang="en" suppressHydrationWarning>
|
25
|
+
<body
|
26
|
+
className={`${fontSans.variable} ${fontMono.variable} font-sans antialiased `}
|
27
|
+
>
|
28
|
+
<Providers>
|
29
|
+
<DefaultLayout>{children}</DefaultLayout>
|
30
|
+
<Toaster />
|
31
|
+
</Providers>
|
32
|
+
</body>
|
33
|
+
</html>
|
34
|
+
);
|
35
|
+
}
|
File without changes
|