diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx
index 5c75be0a..a50da9c6 100644
--- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx
+++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profiles.tsx
@@ -1,6 +1,9 @@
'use client';
+import { TableButtons } from '@/components/data-table';
import { ProfilesTable } from '@/components/profiles/table';
+import { Input } from '@/components/ui/input';
+import { useDebounceValue } from '@/hooks/useDebounceValue';
import { api } from '@/trpc/client';
import { parseAsInteger, useQueryState } from 'nuqs';
@@ -14,12 +17,17 @@ const Events = ({ projectId }: Props) => {
'cursor',
parseAsInteger.withDefault(0)
);
+ const [search, setSearch] = useQueryState('search', {
+ defaultValue: '',
+ shallow: true,
+ });
+ const debouncedSearch = useDebounceValue(search, 500);
const query = api.profile.list.useQuery(
{
cursor,
projectId,
take: 50,
- // filters,
+ search: debouncedSearch,
},
{
keepPreviousData: true,
@@ -28,6 +36,13 @@ const Events = ({ projectId }: Props) => {
return (
);
diff --git a/apps/dashboard/src/components/profiles/table/index.tsx b/apps/dashboard/src/components/profiles/table/index.tsx
index 6672c2a6..888b3ce3 100644
--- a/apps/dashboard/src/components/profiles/table/index.tsx
+++ b/apps/dashboard/src/components/profiles/table/index.tsx
@@ -1,3 +1,4 @@
+import { memo } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import { DataTable } from '@/components/data-table';
import { FullPageEmptyState } from '@/components/full-page-empty-state';
@@ -5,6 +6,7 @@ import { Pagination } from '@/components/pagination';
import { Button } from '@/components/ui/button';
import { TableSkeleton } from '@/components/ui/table';
import type { UseQueryResult } from '@tanstack/react-query';
+import isEqual from 'lodash.isequal';
import { GanttChartIcon } from 'lucide-react';
import type { IServiceProfile } from '@openpanel/db';
@@ -22,44 +24,53 @@ type Props =
setCursor: Dispatch>;
});
-export const ProfilesTable = ({ type, query, ...props }: Props) => {
- const columns = useColumns(type);
- const { data, isFetching, isLoading } = query;
+export const ProfilesTable = memo(
+ ({ type, query, ...props }: Props) => {
+ console.log('re-render');
- if (isLoading) {
- return ;
- }
+ const columns = useColumns(type);
+ const { data, isFetching, isLoading } = query;
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (data?.length === 0) {
+ return (
+
+ Could not find any profiles
+ {'cursor' in props && props.cursor !== 0 && (
+
+ )}
+
+ );
+ }
- if (data?.length === 0) {
return (
-
- Could not find any profiles
- {'cursor' in props && props.cursor !== 0 && (
-
+ <>
+
+ {'cursor' in props && (
+
)}
-
+ >
);
+ },
+ (prevProps, nextProps) => {
+ return isEqual(prevProps.query.data, nextProps.query.data);
}
+);
- return (
- <>
-
- {'cursor' in props && (
-
- )}
- >
- );
-};
+ProfilesTable.displayName = 'ProfilesTable';
diff --git a/packages/db/src/services/profile.service.ts b/packages/db/src/services/profile.service.ts
index 9155b6bc..a54e3ff1 100644
--- a/packages/db/src/services/profile.service.ts
+++ b/packages/db/src/services/profile.service.ts
@@ -66,6 +66,7 @@ interface GetProfileListOptions {
take: number;
cursor?: number;
filters?: IChartEventFilter[];
+ search?: string;
}
export async function getProfiles(ids: string[]) {
@@ -90,6 +91,7 @@ export async function getProfileList({
cursor,
projectId,
filters,
+ search,
}: GetProfileListOptions) {
const { sb, getSql } = createSqlBuilder();
sb.from = 'profiles FINAL';
@@ -98,6 +100,13 @@ export async function getProfileList({
sb.limit = take;
sb.offset = Math.max(0, (cursor ?? 0) * take);
sb.orderBy.created_at = 'created_at DESC';
+ if (search) {
+ if (search.includes('@')) {
+ sb.where.email = `email ILIKE '%${search}%'`;
+ } else {
+ sb.where.first_name = `first_name ILIKE '%${search}%' OR last_name ILIKE '%${search}%'`;
+ }
+ }
const data = await chQuery(getSql());
return data.map(transformProfile);
}
@@ -107,7 +116,7 @@ export async function getProfileListCount({
filters,
}: Omit) {
const { sb, getSql } = createSqlBuilder();
- sb.from = 'profiles FINAL';
+ sb.from = 'profiles';
sb.select.count = 'count(id) as count';
sb.where.project_id = `project_id = ${escape(projectId)}`;
sb.groupBy.project_id = 'project_id';
diff --git a/packages/trpc/src/routers/profile.ts b/packages/trpc/src/routers/profile.ts
index 730064bd..af9307d8 100644
--- a/packages/trpc/src/routers/profile.ts
+++ b/packages/trpc/src/routers/profile.ts
@@ -40,11 +40,12 @@ export const profileRouter = createTRPCRouter({
projectId: z.string(),
cursor: z.number().optional(),
take: z.number().default(50),
+ search: z.string().optional(),
// filters: z.array(zChartEventFilter).default([]),
})
)
- .query(async ({ input: { projectId, cursor, take } }) => {
- return getProfileList({ projectId, cursor, take });
+ .query(async ({ input: { projectId, cursor, take, search } }) => {
+ return getProfileList({ projectId, cursor, take, search });
}),
powerUsers: protectedProcedure