Skip to content

Commit

Permalink
Add peer multiselect, optimize dropdown performance for peer selectio…
Browse files Browse the repository at this point in the history
…n, remove 'all' group from some dropdowns, various ui / ux optimizations
  • Loading branch information
heisbrot committed Aug 13, 2024
1 parent d272651 commit a6f42a2
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 167 deletions.
1 change: 1 addition & 0 deletions src/app/(dashboard)/peer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ function PeerOverview() {
disabled={isUser}
onChange={setSelectedGroups}
values={selectedGroups}
hideAllGroup={true}
peer={peer}
/>
</FullTooltip>
Expand Down
31 changes: 16 additions & 15 deletions src/app/(dashboard)/peers/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import Breadcrumbs from "@components/Breadcrumbs";
import InlineLink from "@components/InlineLink";
import Paragraph from "@components/Paragraph";
import SkeletonTable from "@components/skeletons/SkeletonTable";
import useFetchApi from "@utils/api";
import { usePortalElement } from "@hooks/usePortalElement";
import { ExternalLinkIcon } from "lucide-react";
import React, { lazy, Suspense, useEffect } from "react";
import React, { lazy, Suspense } from "react";
import PeerIcon from "@/assets/icons/PeerIcon";
import { useGroups } from "@/contexts/GroupsProvider";
import PeersProvider, { usePeers } from "@/contexts/PeersProvider";
import { useLoggedInUser, useUsers } from "@/contexts/UsersProvider";
import { Peer } from "@/interfaces/Peer";
import PageContainer from "@/layouts/PageContainer";
import { SetupModalContent } from "@/modules/setup-netbird-modal/SetupModal";

Expand All @@ -21,24 +20,22 @@ export default function Peers() {

return (
<PageContainer>
{permission?.dashboard_view === "blocked" ? (
{permission.dashboard_view === "blocked" ? (
<PeersBlockedView />
) : (
<PeersView />
<PeersProvider>
<PeersView />
</PeersProvider>
)}
</PageContainer>
);
}

function PeersView() {
const { data: peers, isLoading } = useFetchApi<Peer[]>("/peers");
const { peers, isLoading } = usePeers();
const { users } = useUsers();
const { refresh } = useGroups();

useEffect(() => {
refresh();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const { ref: headingRef, portalTarget } =
usePortalElement<HTMLHeadingElement>();

const peersWithUser = peers?.map((peer) => {
if (!users) return peer;
Expand All @@ -58,7 +55,7 @@ function PeersView() {
icon={<PeerIcon size={13} />}
/>
</Breadcrumbs>
<h1>{peers && peers.length > 1 ? `${peers.length} Peers` : "Peers"}</h1>
<h1 ref={headingRef}>Peers</h1>
<Paragraph>
A list of all machines and devices connected to your private network.
Use this view to manage peers.
Expand All @@ -76,7 +73,11 @@ function PeersView() {
</Paragraph>
</div>
<Suspense fallback={<SkeletonTable />}>
<PeersTable isLoading={isLoading} peers={peersWithUser} />
<PeersTable
isLoading={isLoading}
peers={peersWithUser}
headingTarget={portalTarget}
/>
</Suspense>
</>
);
Expand Down
26 changes: 16 additions & 10 deletions src/app/(dashboard)/team/user/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ function UserOverview({ user }: Props) {
)}
</div>

<div className={"flex gap-10 w-full mt-8 max-w-6xl"}>
<div className={"flex gap-10 w-full mt-8 max-w-6xl items-start"}>
<UserInformationCard user={user} />
<div className={"flex flex-col gap-8 w-1/2 "}>
{!user.is_service_user && (
Expand All @@ -200,6 +200,7 @@ function UserOverview({ user }: Props) {
disabled={isUser}
onChange={setSelectedGroups}
values={selectedGroups}
hideAllGroup={true}
/>
</div>
)}
Expand All @@ -214,6 +215,8 @@ function UserOverview({ user }: Props) {
<UserRoleSelector
value={role}
onChange={setRole}
hideOwner={user.is_service_user}
currentUser={user}
disabled={
isLoggedInUser ||
!isOwnerOrAdmin ||
Expand Down Expand Up @@ -301,15 +304,18 @@ function UserInformationCard({ user }: { user: User }) {

{!isServiceUser && (
<>
<Card.ListItem
label={
<>
<Ban size={16} />
Block User
</>
}
value={<UserBlockCell user={user} isUserPage={true} />}
/>
{!user.is_current && user.role != Role.Owner && (
<Card.ListItem
label={
<>
<Ban size={16} />
Block User
</>
}
value={<UserBlockCell user={user} isUserPage={true} />}
/>
)}

<Card.ListItem
label={
<>
Expand Down
5 changes: 5 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,9 @@ p {

.stepper-bg-variant .step-circle {
@apply !border-[#1d2024];
}

.webkit-scroll{
-webkit-overflow-scrolling: touch;
-webkit-transform: translate3d(0, 0, 0);
}
157 changes: 26 additions & 131 deletions src/modules/posture-checks/modal/PostureCheckBrowseModal.tsx
Original file line number Diff line number Diff line change
@@ -1,138 +1,33 @@
import Button from "@components/Button";
import { Checkbox } from "@components/Checkbox";
import { DataTable } from "@components/table/DataTable";
import DataTableHeader from "@components/table/DataTableHeader";
import DataTableRefreshButton from "@components/table/DataTableRefreshButton";
import { useLocalStorage } from "@hooks/useLocalStorage";
import {
ColumnDef,
RowSelectionState,
SortingState,
} from "@tanstack/react-table";
import useFetchApi from "@utils/api";
import { usePathname } from "next/navigation";
import React, { useState } from "react";
import { useSWRConfig } from "swr";
import { Modal, ModalContent } from "@components/modal/Modal";
import { cn } from "@utils/helpers";
import * as React from "react";
import { PostureCheck } from "@/interfaces/PostureCheck";
import { PostureCheckChecksCell } from "@/modules/posture-checks/table/cells/PostureCheckChecksCell";
import { PostureCheckNameCell } from "@/modules/posture-checks/table/cells/PostureCheckNameCell";
import PostureCheckBrowseTable from "@/modules/posture-checks/table/PostureCheckBrowseTable";

type Props = {
onAdd: (checks: PostureCheck[]) => void;
onSuccess: (checks: PostureCheck[]) => void;
open: boolean;
onOpenChange: (open: boolean) => void;
};

export default function PostureCheckBrowseTable({ onAdd }: Readonly<Props>) {
const { data: postureChecks, isLoading } =
useFetchApi<PostureCheck[]>("/posture-checks");
const { mutate } = useSWRConfig();
const path = usePathname();

// Default sorting state of the table
const [sorting, setSorting] = useLocalStorage<SortingState>(
"netbird-table-sort" + path,
[
{
id: "name",
desc: true,
},
],
);

const [selectedRows, setSelectedRows] = useState<RowSelectionState>({});

export const PostureCheckBrowseModal = ({
onSuccess,
open,
onOpenChange,
}: Props) => {
return (
<div className={""}>
<DataTable
showResetFilterButton={false}
rowSelection={selectedRows}
setRowSelection={setSelectedRows}
isLoading={isLoading}
text={"Posture Check"}
sorting={sorting}
wrapperClassName={""}
setSorting={setSorting}
columns={PostureChecksColumns}
showHeader={true}
columnVisibility={{
description: false,
}}
tableClassName={"mt-6 !border-0"}
rowClassName={"!border-b-0 px-10"}
data={postureChecks}
searchPlaceholder={"Search by name and description..."}
onRowClick={(row) => row.toggleSelected()}
rightSide={(table) => (
<>
{postureChecks && postureChecks?.length > 0 && (
<Button
variant={"primary"}
className={"ml-auto"}
onClick={() =>
onAdd(
table.getSelectedRowModel().rows.map((row) => row.original),
)
}
disabled={table.getSelectedRowModel().rows.length <= 0}
>
Add Posture Checks ({table.getSelectedRowModel().rows.length})
</Button>
)}
</>
)}
<Modal open={open} onOpenChange={onOpenChange} key={open ? 1 : 0}>
<ModalContent
maxWidthClass={cn("relative", "max-w-2xl")}
className={"pb-0"}
showClose={false}
>
{() => {
return (
<DataTableRefreshButton
isDisabled={postureChecks?.length == 0}
onClick={() => {
mutate("/posture-checks");
}}
/>
);
}}
</DataTable>
</div>
);
}

export const PostureChecksColumns: ColumnDef<PostureCheck>[] = [
{
id: "select",
header: ({ table }) => (
<div className={"min-w-[20px] max-w-[20px]"}>
<Checkbox
checked={table.getIsAllPageRowsSelected()}
onCheckedChange={(value) => table.toggleAllRowsSelected(!!value)}
aria-label="Select all"
/>
</div>
),
cell: ({ row }) => (
<div className={"min-w-[20px] max-w-[20px]"}>
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
<PostureCheckBrowseTable
onAdd={(checks) => {
onSuccess(checks);
onOpenChange(false);
}}
/>
</div>
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "name",
header: ({ column }) => {
return <DataTableHeader column={column}>Name</DataTableHeader>;
},
cell: ({ row }) => (
<PostureCheckNameCell small={true} check={row.original} />
),
},
{
accessorKey: "id",
header: ({ column }) => {
return <DataTableHeader column={column}>Checks</DataTableHeader>;
},
cell: ({ row }) => <PostureCheckChecksCell check={row.original} />,
},
];
</ModalContent>
</Modal>
);
};
29 changes: 18 additions & 11 deletions src/modules/posture-checks/table/PostureCheckBrowseTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import { DataTable } from "@components/table/DataTable";
import DataTableHeader from "@components/table/DataTableHeader";
import DataTableRefreshButton from "@components/table/DataTableRefreshButton";
import { useLocalStorage } from "@hooks/useLocalStorage";
import type { ColumnDef, SortingState } from "@tanstack/react-table";
import {
ColumnDef,
RowSelectionState,
SortingState,
} from "@tanstack/react-table";
import useFetchApi from "@utils/api";
import { usePathname } from "next/navigation";
import React from "react";
import React, { useState } from "react";
import { useSWRConfig } from "swr";
import { PostureCheck } from "@/interfaces/PostureCheck";
import { PostureCheckChecksCell } from "@/modules/posture-checks/table/cells/PostureCheckChecksCell";
Expand All @@ -17,7 +21,7 @@ type Props = {
onAdd: (checks: PostureCheck[]) => void;
};

export default function PostureCheckBrowseTable({ onAdd }: Props) {
export default function PostureCheckBrowseTable({ onAdd }: Readonly<Props>) {
const { data: postureChecks, isLoading } =
useFetchApi<PostureCheck[]>("/posture-checks");
const { mutate } = useSWRConfig();
Expand All @@ -34,9 +38,14 @@ export default function PostureCheckBrowseTable({ onAdd }: Props) {
],
);

const [selectedRows, setSelectedRows] = useState<RowSelectionState>({});

return (
<div className={""}>
<DataTable
showResetFilterButton={false}
rowSelection={selectedRows}
setRowSelection={setSelectedRows}
isLoading={isLoading}
text={"Posture Check"}
sorting={sorting}
Expand Down Expand Up @@ -73,14 +82,12 @@ export default function PostureCheckBrowseTable({ onAdd }: Props) {
>
{() => {
return (
<>
<DataTableRefreshButton
isDisabled={postureChecks?.length == 0}
onClick={() => {
mutate("/posture-checks");
}}
/>
</>
<DataTableRefreshButton
isDisabled={postureChecks?.length == 0}
onClick={() => {
mutate("/posture-checks");
}}
/>
);
}}
</DataTable>
Expand Down

0 comments on commit a6f42a2

Please sign in to comment.