mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 07:25:48 +01:00
✨ Add tRPC user query
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
ThemeIcon,
|
ThemeIcon,
|
||||||
UnstyledButton,
|
UnstyledButton,
|
||||||
|
useMantineTheme,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
IconAlertTriangle,
|
IconAlertTriangle,
|
||||||
@@ -47,11 +48,12 @@ interface MainLayoutProps {
|
|||||||
export const MainLayout = ({ children }: MainLayoutProps) => {
|
export const MainLayout = ({ children }: MainLayoutProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { attributes } = usePackageAttributesStore();
|
const { attributes } = usePackageAttributesStore();
|
||||||
|
const theme = useMantineTheme();
|
||||||
return (
|
return (
|
||||||
<AppShell
|
<AppShell
|
||||||
styles={{
|
styles={{
|
||||||
root: {
|
root: {
|
||||||
background: '#f1f1f1',
|
background: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[1],
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
navbar={
|
navbar={
|
||||||
|
|||||||
@@ -1,12 +1,98 @@
|
|||||||
import { Title } from "@mantine/core";
|
import {
|
||||||
import { MainLayout } from "~/components/layout/admin/main-admin.layout";
|
ActionIcon,
|
||||||
|
Autocomplete,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
Group,
|
||||||
|
Pagination,
|
||||||
|
SegmentedControl,
|
||||||
|
Table,
|
||||||
|
Text,
|
||||||
|
Title,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { IconPlus, IconTrash } from '@tabler/icons-react';
|
||||||
|
import Head from 'next/head';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { MainLayout } from '~/components/layout/admin/main-admin.layout';
|
||||||
|
import { api } from '~/utils/api';
|
||||||
|
|
||||||
const ManageUsersPage = () => {
|
const ManageUsersPage = () => {
|
||||||
|
const { isLoading, data, fetchNextPage, fetchPreviousPage } = api.user.getAll.useInfiniteQuery(
|
||||||
|
{
|
||||||
|
limit: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const [activePage, _] = useState(1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<Title>Manage users</Title>
|
<Head>
|
||||||
|
<title>Users • Homarr</title>
|
||||||
|
</Head>
|
||||||
|
<Title mb="xl">Manage users</Title>
|
||||||
|
|
||||||
|
<Group position="apart" mb="md">
|
||||||
|
<SegmentedControl
|
||||||
|
data={[
|
||||||
|
{ label: 'Active', value: 'active' },
|
||||||
|
{ label: 'Inactive', value: 'inactive' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Flex columnGap={10}>
|
||||||
|
<Autocomplete
|
||||||
|
placeholder="Filter"
|
||||||
|
data={['React', 'Angular', 'Svelte', 'Vue']}
|
||||||
|
variant="filled"
|
||||||
|
/>
|
||||||
|
<Button leftIcon={<IconPlus size="1rem" />} variant="default">
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{data && (
|
||||||
|
<>
|
||||||
|
<Table mb="md" withBorder highlightOnHover>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>User</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{data.pages[0].users.map((user) => (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Group position="apart">
|
||||||
|
<Group spacing="xs">
|
||||||
|
<Avatar size="sm" />
|
||||||
|
<Text>{user.name}</Text>
|
||||||
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<ActionIcon color="red" variant="light">
|
||||||
|
<IconTrash size="1rem" />
|
||||||
|
</ActionIcon>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
<Pagination
|
||||||
|
total={data.pages.length}
|
||||||
|
value={activePage}
|
||||||
|
onNextPage={fetchNextPage}
|
||||||
|
onPreviousPage={fetchPreviousPage}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ManageUsersPage;
|
export default ManageUsersPage;
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import { Title } from "@mantine/core";
|
import { Title } from '@mantine/core';
|
||||||
import { MainLayout } from "~/components/layout/admin/main-admin.layout";
|
import { Head } from 'next/document';
|
||||||
|
import { MainLayout } from '~/components/layout/admin/main-admin.layout';
|
||||||
|
|
||||||
const ManageUserInvitesPage = () => {
|
const ManageUserInvitesPage = () => {
|
||||||
return (
|
return (
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
|
<Head>
|
||||||
|
<title>User invites • Homarr</title>
|
||||||
|
</Head>
|
||||||
<Title>Manage user invites</Title>
|
<Title>Manage user invites</Title>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ManageUserInvitesPage;
|
export default ManageUserInvitesPage;
|
||||||
@@ -110,7 +110,7 @@ export const userRouter = createTRPCRouter({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
getWithSettings: protectedProcedure.query(async ({ ctx }) => {
|
getWithSettings: protectedProcedure.query(async ({ ctx, input }) => {
|
||||||
const user = await ctx.prisma.user.findUnique({
|
const user = await ctx.prisma.user.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: ctx.session?.user?.id,
|
id: ctx.session?.user?.id,
|
||||||
@@ -133,4 +133,36 @@ export const userRouter = createTRPCRouter({
|
|||||||
settings: user.settings,
|
settings: user.settings,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
getAll: publicProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
limit: z.number().min(1).max(100).nullish(),
|
||||||
|
cursor: z.number().nullish(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const limit = input.limit ?? 50;
|
||||||
|
const cursor = input.cursor;
|
||||||
|
const users = await ctx.prisma.user.findMany({
|
||||||
|
take: limit + 1, // get an extra item at the end which we'll use as next cursor
|
||||||
|
cursor: cursor ? { myCursor: cursor } : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
let nextCursor: typeof cursor | undefined = undefined;
|
||||||
|
if (users.length > limit) {
|
||||||
|
const nextItem = users.pop();
|
||||||
|
nextCursor = nextItem!.myCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
users: users.map((user) => ({
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
emailVerified: user.emailVerified
|
||||||
|
})),
|
||||||
|
nextCursor,
|
||||||
|
};
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user