mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-28 07:46:36 +00:00
Fix various ui bugs
This commit is contained in:
@@ -6,7 +6,7 @@ import { createApiClient } from "@app/lib/api";
|
|||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { LogDataTable } from "@app/components/LogDataTable";
|
import { getStoredPageSize, LogDataTable, setStoredPageSize } from "@app/components/LogDataTable";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
import { DateTimeValue } from "@app/components/DateTimePicker";
|
import { DateTimeValue } from "@app/components/DateTimePicker";
|
||||||
import { ArrowUpRight, Key, User } from "lucide-react";
|
import { ArrowUpRight, Key, User } from "lucide-react";
|
||||||
@@ -56,9 +56,13 @@ export default function GeneralPage() {
|
|||||||
// Pagination state
|
// Pagination state
|
||||||
const [totalCount, setTotalCount] = useState<number>(0);
|
const [totalCount, setTotalCount] = useState<number>(0);
|
||||||
const [currentPage, setCurrentPage] = useState<number>(0);
|
const [currentPage, setCurrentPage] = useState<number>(0);
|
||||||
const [pageSize, setPageSize] = useState<number>(20);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
// Initialize page size from storage or default
|
||||||
|
const [pageSize, setPageSize] = useState<number>(() => {
|
||||||
|
return getStoredPageSize("access-audit-logs", 20);
|
||||||
|
});
|
||||||
|
|
||||||
// Set default date range to last 24 hours
|
// Set default date range to last 24 hours
|
||||||
const getDefaultDateRange = () => {
|
const getDefaultDateRange = () => {
|
||||||
// if the time is in the url params, use that instead
|
// if the time is in the url params, use that instead
|
||||||
@@ -133,6 +137,7 @@ export default function GeneralPage() {
|
|||||||
// Handle page size changes
|
// Handle page size changes
|
||||||
const handlePageSizeChange = (newPageSize: number) => {
|
const handlePageSizeChange = (newPageSize: number) => {
|
||||||
setPageSize(newPageSize);
|
setPageSize(newPageSize);
|
||||||
|
setStoredPageSize(newPageSize, "access-audit-logs");
|
||||||
setCurrentPage(0); // Reset to first page when changing page size
|
setCurrentPage(0); // Reset to first page when changing page size
|
||||||
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
|
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
|
||||||
};
|
};
|
||||||
@@ -581,7 +586,6 @@ export default function GeneralPage() {
|
|||||||
<LogDataTable
|
<LogDataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={rows}
|
data={rows}
|
||||||
persistPageSize="access-logs-table"
|
|
||||||
title={t("accessLogs")}
|
title={t("accessLogs")}
|
||||||
onRefresh={refreshData}
|
onRefresh={refreshData}
|
||||||
isRefreshing={isRefreshing}
|
isRefreshing={isRefreshing}
|
||||||
@@ -599,10 +603,10 @@ export default function GeneralPage() {
|
|||||||
// Server-side pagination props
|
// Server-side pagination props
|
||||||
totalCount={totalCount}
|
totalCount={totalCount}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
|
pageSize={pageSize}
|
||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onPageSizeChange={handlePageSizeChange}
|
onPageSizeChange={handlePageSizeChange}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
defaultPageSize={pageSize}
|
|
||||||
// Row expansion props
|
// Row expansion props
|
||||||
expandable={true}
|
expandable={true}
|
||||||
renderExpandedRow={renderExpandedRow}
|
renderExpandedRow={renderExpandedRow}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createApiClient } from "@app/lib/api";
|
|||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { LogDataTable } from "@app/components/LogDataTable";
|
import { getStoredPageSize, LogDataTable, setStoredPageSize } from "@app/components/LogDataTable";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
import { DateTimeValue } from "@app/components/DateTimePicker";
|
import { DateTimeValue } from "@app/components/DateTimePicker";
|
||||||
import { Key, User } from "lucide-react";
|
import { Key, User } from "lucide-react";
|
||||||
@@ -44,9 +44,13 @@ export default function GeneralPage() {
|
|||||||
// Pagination state
|
// Pagination state
|
||||||
const [totalCount, setTotalCount] = useState<number>(0);
|
const [totalCount, setTotalCount] = useState<number>(0);
|
||||||
const [currentPage, setCurrentPage] = useState<number>(0);
|
const [currentPage, setCurrentPage] = useState<number>(0);
|
||||||
const [pageSize, setPageSize] = useState<number>(20);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
// Initialize page size from storage or default
|
||||||
|
const [pageSize, setPageSize] = useState<number>(() => {
|
||||||
|
return getStoredPageSize("action-audit-logs", 20);
|
||||||
|
});
|
||||||
|
|
||||||
// Set default date range to last 24 hours
|
// Set default date range to last 24 hours
|
||||||
const getDefaultDateRange = () => {
|
const getDefaultDateRange = () => {
|
||||||
// if the time is in the url params, use that instead
|
// if the time is in the url params, use that instead
|
||||||
@@ -121,6 +125,7 @@ export default function GeneralPage() {
|
|||||||
// Handle page size changes
|
// Handle page size changes
|
||||||
const handlePageSizeChange = (newPageSize: number) => {
|
const handlePageSizeChange = (newPageSize: number) => {
|
||||||
setPageSize(newPageSize);
|
setPageSize(newPageSize);
|
||||||
|
setStoredPageSize(newPageSize, "action-audit-logs");
|
||||||
setCurrentPage(0); // Reset to first page when changing page size
|
setCurrentPage(0); // Reset to first page when changing page size
|
||||||
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
|
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
|
||||||
};
|
};
|
||||||
@@ -433,7 +438,6 @@ export default function GeneralPage() {
|
|||||||
<LogDataTable
|
<LogDataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={rows}
|
data={rows}
|
||||||
persistPageSize="action-logs-table"
|
|
||||||
title={t("actionLogs")}
|
title={t("actionLogs")}
|
||||||
searchPlaceholder={t("searchLogs")}
|
searchPlaceholder={t("searchLogs")}
|
||||||
searchColumn="action"
|
searchColumn="action"
|
||||||
@@ -453,10 +457,10 @@ export default function GeneralPage() {
|
|||||||
// Server-side pagination props
|
// Server-side pagination props
|
||||||
totalCount={totalCount}
|
totalCount={totalCount}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
|
pageSize={pageSize}
|
||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onPageSizeChange={handlePageSizeChange}
|
onPageSizeChange={handlePageSizeChange}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
defaultPageSize={pageSize}
|
|
||||||
// Row expansion props
|
// Row expansion props
|
||||||
expandable={true}
|
expandable={true}
|
||||||
renderExpandedRow={renderExpandedRow}
|
renderExpandedRow={renderExpandedRow}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createApiClient } from "@app/lib/api";
|
|||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { LogDataTable } from "@app/components/LogDataTable";
|
import { getStoredPageSize, LogDataTable, setStoredPageSize } from "@app/components/LogDataTable";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
import { DateTimeValue } from "@app/components/DateTimePicker";
|
import { DateTimeValue } from "@app/components/DateTimePicker";
|
||||||
import { Key, RouteOff, User, Lock, Unlock, ArrowUpRight } from "lucide-react";
|
import { Key, RouteOff, User, Lock, Unlock, ArrowUpRight } from "lucide-react";
|
||||||
@@ -28,9 +28,13 @@ export default function GeneralPage() {
|
|||||||
// Pagination state
|
// Pagination state
|
||||||
const [totalCount, setTotalCount] = useState<number>(0);
|
const [totalCount, setTotalCount] = useState<number>(0);
|
||||||
const [currentPage, setCurrentPage] = useState<number>(0);
|
const [currentPage, setCurrentPage] = useState<number>(0);
|
||||||
const [pageSize, setPageSize] = useState<number>(20);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
// Initialize page size from storage or default
|
||||||
|
const [pageSize, setPageSize] = useState<number>(() => {
|
||||||
|
return getStoredPageSize("request-audit-logs", 20);
|
||||||
|
});
|
||||||
|
|
||||||
const [filterAttributes, setFilterAttributes] = useState<{
|
const [filterAttributes, setFilterAttributes] = useState<{
|
||||||
actors: string[];
|
actors: string[];
|
||||||
resources: {
|
resources: {
|
||||||
@@ -143,6 +147,7 @@ export default function GeneralPage() {
|
|||||||
// Handle page size changes
|
// Handle page size changes
|
||||||
const handlePageSizeChange = (newPageSize: number) => {
|
const handlePageSizeChange = (newPageSize: number) => {
|
||||||
setPageSize(newPageSize);
|
setPageSize(newPageSize);
|
||||||
|
setStoredPageSize(newPageSize, "request-audit-logs");
|
||||||
setCurrentPage(0); // Reset to first page when changing page size
|
setCurrentPage(0); // Reset to first page when changing page size
|
||||||
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
|
queryDateTime(dateRange.startDate, dateRange.endDate, 0, newPageSize);
|
||||||
};
|
};
|
||||||
@@ -753,7 +758,6 @@ export default function GeneralPage() {
|
|||||||
<LogDataTable
|
<LogDataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={rows}
|
data={rows}
|
||||||
persistPageSize="request-logs-table"
|
|
||||||
title={t("requestLogs")}
|
title={t("requestLogs")}
|
||||||
searchPlaceholder={t("searchLogs")}
|
searchPlaceholder={t("searchLogs")}
|
||||||
searchColumn="host"
|
searchColumn="host"
|
||||||
@@ -776,7 +780,7 @@ export default function GeneralPage() {
|
|||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onPageSizeChange={handlePageSizeChange}
|
onPageSizeChange={handlePageSizeChange}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
defaultPageSize={pageSize}
|
pageSize={pageSize}
|
||||||
// Row expansion props
|
// Row expansion props
|
||||||
expandable={true}
|
expandable={true}
|
||||||
renderExpandedRow={renderExpandedRow}
|
renderExpandedRow={renderExpandedRow}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export function DataTablePagination<TData>({
|
|||||||
value={`${table.getState().pagination.pageSize}`}
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
onValueChange={handlePageSizeChange}
|
onValueChange={handlePageSizeChange}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 w-[70px]">
|
<SelectTrigger className="h-8 w-[73px]">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={table.getState().pagination.pageSize}
|
placeholder={table.getState().pagination.pageSize}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const STORAGE_KEYS = {
|
|||||||
tableId ? `${tableId}-size` : STORAGE_KEYS.PAGE_SIZE
|
tableId ? `${tableId}-size` : STORAGE_KEYS.PAGE_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStoredPageSize = (tableId?: string, defaultSize = 20): number => {
|
export const getStoredPageSize = (tableId?: string, defaultSize = 20): number => {
|
||||||
if (typeof window === "undefined") return defaultSize;
|
if (typeof window === "undefined") return defaultSize;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -68,7 +68,7 @@ const getStoredPageSize = (tableId?: string, defaultSize = 20): number => {
|
|||||||
return defaultSize;
|
return defaultSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setStoredPageSize = (pageSize: number, tableId?: string): void => {
|
export const setStoredPageSize = (pageSize: number, tableId?: string): void => {
|
||||||
if (typeof window === "undefined") return;
|
if (typeof window === "undefined") return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -102,8 +102,6 @@ type DataTableProps<TData, TValue> = {
|
|||||||
};
|
};
|
||||||
tabs?: TabFilter[];
|
tabs?: TabFilter[];
|
||||||
defaultTab?: string;
|
defaultTab?: string;
|
||||||
persistPageSize?: boolean | string;
|
|
||||||
defaultPageSize?: number;
|
|
||||||
onDateRangeChange?: (
|
onDateRangeChange?: (
|
||||||
startDate: DateTimeValue,
|
startDate: DateTimeValue,
|
||||||
endDate: DateTimeValue
|
endDate: DateTimeValue
|
||||||
@@ -114,6 +112,7 @@ type DataTableProps<TData, TValue> = {
|
|||||||
};
|
};
|
||||||
// Server-side pagination props
|
// Server-side pagination props
|
||||||
totalCount?: number;
|
totalCount?: number;
|
||||||
|
pageSize: number;
|
||||||
currentPage?: number;
|
currentPage?: number;
|
||||||
onPageChange?: (page: number) => void;
|
onPageChange?: (page: number) => void;
|
||||||
onPageSizeChange?: (pageSize: number) => void;
|
onPageSizeChange?: (pageSize: number) => void;
|
||||||
@@ -136,9 +135,8 @@ export function LogDataTable<TData, TValue>({
|
|||||||
defaultSort,
|
defaultSort,
|
||||||
tabs,
|
tabs,
|
||||||
defaultTab,
|
defaultTab,
|
||||||
persistPageSize = false,
|
|
||||||
defaultPageSize = 20,
|
|
||||||
onDateRangeChange,
|
onDateRangeChange,
|
||||||
|
pageSize,
|
||||||
dateRange,
|
dateRange,
|
||||||
totalCount,
|
totalCount,
|
||||||
currentPage = 0,
|
currentPage = 0,
|
||||||
@@ -150,18 +148,6 @@ export function LogDataTable<TData, TValue>({
|
|||||||
}: DataTableProps<TData, TValue>) {
|
}: DataTableProps<TData, TValue>) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
// Determine table identifier for storage
|
|
||||||
const tableId =
|
|
||||||
typeof persistPageSize === "string" ? persistPageSize : undefined;
|
|
||||||
|
|
||||||
// Initialize page size from storage or default
|
|
||||||
const [pageSize, setPageSize] = useState<number>(() => {
|
|
||||||
if (persistPageSize) {
|
|
||||||
return getStoredPageSize(tableId, defaultPageSize);
|
|
||||||
}
|
|
||||||
return defaultPageSize;
|
|
||||||
});
|
|
||||||
|
|
||||||
const [sorting, setSorting] = useState<SortingState>(
|
const [sorting, setSorting] = useState<SortingState>(
|
||||||
defaultSort ? [defaultSort] : []
|
defaultSort ? [defaultSort] : []
|
||||||
);
|
);
|
||||||
@@ -289,17 +275,17 @@ export function LogDataTable<TData, TValue>({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const currentPageSize = table.getState().pagination.pageSize;
|
// const currentPageSize = table.getState().pagination.pageSize;
|
||||||
if (currentPageSize !== pageSize) {
|
// if (currentPageSize !== pageSize) {
|
||||||
table.setPageSize(pageSize);
|
// table.setPageSize(pageSize);
|
||||||
|
|
||||||
// Persist to localStorage if enabled
|
// // Persist to localStorage if enabled
|
||||||
if (persistPageSize) {
|
// if (persistPageSize) {
|
||||||
setStoredPageSize(pageSize, tableId);
|
// setStoredPageSize(pageSize, tableId);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}, [pageSize, table, persistPageSize, tableId]);
|
// }, [pageSize, table, persistPageSize, tableId]);
|
||||||
|
|
||||||
// Update table page index when currentPage prop changes (server pagination)
|
// Update table page index when currentPage prop changes (server pagination)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -319,13 +305,13 @@ export function LogDataTable<TData, TValue>({
|
|||||||
|
|
||||||
// Enhanced pagination component that updates our local state
|
// Enhanced pagination component that updates our local state
|
||||||
const handlePageSizeChange = (newPageSize: number) => {
|
const handlePageSizeChange = (newPageSize: number) => {
|
||||||
setPageSize(newPageSize);
|
// setPageSize(newPageSize);
|
||||||
table.setPageSize(newPageSize);
|
table.setPageSize(newPageSize);
|
||||||
|
|
||||||
// Persist immediately when changed
|
// Persist immediately when changed
|
||||||
if (persistPageSize) {
|
// if (persistPageSize) {
|
||||||
setStoredPageSize(newPageSize, tableId);
|
// setStoredPageSize(newPageSize, tableId);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// For server pagination, notify parent component
|
// For server pagination, notify parent component
|
||||||
if (isServerPagination && onPageSizeChangeProp) {
|
if (isServerPagination && onPageSizeChangeProp) {
|
||||||
@@ -421,77 +407,75 @@ export function LogDataTable<TData, TValue>({
|
|||||||
table.getRowModel().rows.map((row) => {
|
table.getRowModel().rows.map((row) => {
|
||||||
const isExpanded =
|
const isExpanded =
|
||||||
expandable && expandedRows.has(row.id);
|
expandable && expandedRows.has(row.id);
|
||||||
return (
|
return [
|
||||||
<>
|
<TableRow
|
||||||
<TableRow
|
key={row.id}
|
||||||
key={row.id}
|
data-state={
|
||||||
data-state={
|
row.getIsSelected() &&
|
||||||
row.getIsSelected() &&
|
"selected"
|
||||||
"selected"
|
}
|
||||||
}
|
onClick={() =>
|
||||||
onClick={() =>
|
expandable
|
||||||
expandable
|
? toggleRowExpansion(
|
||||||
? toggleRowExpansion(
|
row.id
|
||||||
row.id
|
)
|
||||||
)
|
: undefined
|
||||||
: undefined
|
}
|
||||||
}
|
className="text-xs" // made smaller
|
||||||
className="text-xs" // made smaller
|
>
|
||||||
>
|
{row
|
||||||
{row
|
.getVisibleCells()
|
||||||
.getVisibleCells()
|
.map((cell) => {
|
||||||
.map((cell) => {
|
const originalRow =
|
||||||
const originalRow =
|
row.original as any;
|
||||||
row.original as any;
|
const actionValue =
|
||||||
const actionValue =
|
originalRow?.action;
|
||||||
originalRow?.action;
|
let className = "";
|
||||||
let className = "";
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof actionValue ===
|
typeof actionValue ===
|
||||||
"boolean"
|
"boolean"
|
||||||
) {
|
) {
|
||||||
className =
|
className =
|
||||||
actionValue
|
actionValue
|
||||||
? "bg-green-100 dark:bg-green-900/50"
|
? "bg-green-100 dark:bg-green-900/50"
|
||||||
: "bg-red-100 dark:bg-red-900/50";
|
: "bg-red-100 dark:bg-red-900/50";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableCell
|
|
||||||
key={cell.id}
|
|
||||||
className={`${className} py-2`} // made smaller
|
|
||||||
>
|
|
||||||
{flexRender(
|
|
||||||
cell.column
|
|
||||||
.columnDef
|
|
||||||
.cell,
|
|
||||||
cell.getContext()
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableRow>
|
|
||||||
{isExpanded &&
|
|
||||||
renderExpandedRow && (
|
|
||||||
<TableRow
|
|
||||||
key={`${row.id}-expanded`}
|
|
||||||
>
|
|
||||||
<TableCell
|
<TableCell
|
||||||
colSpan={
|
key={cell.id}
|
||||||
enhancedColumns.length
|
className={`${className} py-2`} // made smaller
|
||||||
}
|
|
||||||
className="p-4 bg-muted/50"
|
|
||||||
>
|
>
|
||||||
{renderExpandedRow(
|
{flexRender(
|
||||||
row.original
|
cell.column
|
||||||
|
.columnDef
|
||||||
|
.cell,
|
||||||
|
cell.getContext()
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
);
|
||||||
)}
|
})}
|
||||||
</>
|
</TableRow>,
|
||||||
);
|
isExpanded &&
|
||||||
})
|
renderExpandedRow && (
|
||||||
|
<TableRow
|
||||||
|
key={`${row.id}-expanded`}
|
||||||
|
>
|
||||||
|
<TableCell
|
||||||
|
colSpan={
|
||||||
|
enhancedColumns.length
|
||||||
|
}
|
||||||
|
className="p-4 bg-muted/50"
|
||||||
|
>
|
||||||
|
{renderExpandedRow(
|
||||||
|
row.original
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
].filter(Boolean);
|
||||||
|
}).flat()
|
||||||
) : (
|
) : (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
|
|||||||
Reference in New Issue
Block a user