mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-29 06:10:47 +00:00
add sitcky table cols for left and right cols
This commit is contained in:
@@ -2156,5 +2156,6 @@
|
||||
"checkSelectedStatus": "Check Status of Selected",
|
||||
"clients": "Clients",
|
||||
"accessClientSelect": "Select machine clients",
|
||||
"resourceClientDescription": "Machine clients that can access this resource"
|
||||
"resourceClientDescription": "Machine clients that can access this resource",
|
||||
"regenerate": "Regenerate"
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ export function IdpDataTable<TData, TValue>({
|
||||
}}
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="name"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ export default function IdpTable({ idps }: Props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -133,19 +134,12 @@ export default function IdpTable({ idps }: Props) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const siteRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<Link href={`/admin/idp/${siteRow.idpId}/general`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -176,6 +170,14 @@ export default function IdpTable({ idps }: Props) {
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link href={`/admin/idp/${siteRow.idpId}/general`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ export function UsersDataTable<TData, TValue>({
|
||||
searchColumn="email"
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="username"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ export default function UsersTable({ users }: Props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "username",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -201,46 +202,45 @@ export default function UsersTable({ users }: Props) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const r = row.original;
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant={"outline"}
|
||||
onClick={() => {
|
||||
router.push(`/admin/users/${r.id}`);
|
||||
}}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
Open menu
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelected(r);
|
||||
setIsDeleteModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("delete")}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
Open menu
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelected(r);
|
||||
setIsDeleteModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("delete")}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
onClick={() => {
|
||||
router.push(`/admin/users/${r.id}`);
|
||||
}}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ export function ApiKeysDataTable<TData, TValue>({
|
||||
addButtonText={t('apiKeysAdd')}
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="name"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
|
||||
const columns: ColumnDef<ApiKeyRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -120,19 +121,12 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const r = row.original;
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Link href={`/admin/api-keys/${r.id}`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -162,6 +156,14 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link href={`/admin/api-keys/${r.id}`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -157,10 +158,11 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="flex">
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="items-center"
|
||||
@@ -187,6 +189,9 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
|
||||
title={t("blueprints")}
|
||||
searchPlaceholder={t("searchBlueprintProgress")}
|
||||
searchColumn="name"
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="name"
|
||||
stickyRightColumn="actions"
|
||||
onAdd={() => {
|
||||
router.push(`/${orgId}/settings/blueprints/create`);
|
||||
}}
|
||||
|
||||
@@ -334,6 +334,7 @@ export default function ClientsTable({
|
||||
const baseColumns: ColumnDef<ClientRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -531,19 +532,59 @@ export default function ClientsTable({
|
||||
if (hasRowsWithoutUserId) {
|
||||
baseColumns.push({
|
||||
id: "actions",
|
||||
header: () => <span className="p-3">{t("actions")}</span>,
|
||||
enableHiding: false,
|
||||
header: ({ table }) => {
|
||||
const hasHideableColumns = table
|
||||
.getAllColumns()
|
||||
.some((column) => column.getCanHide());
|
||||
if (!hasHideableColumns) {
|
||||
return <span className="p-3"></span>;
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col items-end gap-1 p-3">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="h-7 w-7 p-0">
|
||||
<Columns className="h-4 w-4" />
|
||||
<span className="sr-only">
|
||||
{t("columns") || "Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") || "Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{table
|
||||
.getAllColumns()
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) =>
|
||||
column.toggleVisibility(!!value)
|
||||
}
|
||||
>
|
||||
{typeof column.columnDef.header ===
|
||||
"string"
|
||||
? column.columnDef.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const clientRow = row.original;
|
||||
return !clientRow.userId ? (
|
||||
<div className="flex items-center">
|
||||
<Link
|
||||
href={`/${clientRow.orgId}/settings/clients/${clientRow.id}`}
|
||||
>
|
||||
<Button variant={"outline"}>
|
||||
Edit
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -570,6 +611,14 @@ export default function ClientsTable({
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link
|
||||
href={`/${clientRow.orgId}/settings/clients/${clientRow.id}`}
|
||||
>
|
||||
<Button variant={"outline"}>
|
||||
Edit
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
@@ -693,122 +742,6 @@ export default function ClientsTable({
|
||||
</TabsList>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 sm:justify-end">
|
||||
{currentView === "user" &&
|
||||
userTable
|
||||
.getAllColumns()
|
||||
.some((column) =>
|
||||
column.getCanHide()
|
||||
) && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Columns className="mr-0 sm:mr-2 h-4 w-4" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("columns") ||
|
||||
"Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="w-48"
|
||||
>
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") ||
|
||||
"Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{userTable
|
||||
.getAllColumns()
|
||||
.filter((column) =>
|
||||
column.getCanHide()
|
||||
)
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(
|
||||
value
|
||||
) =>
|
||||
column.toggleVisibility(
|
||||
!!value
|
||||
)
|
||||
}
|
||||
>
|
||||
{typeof column
|
||||
.columnDef
|
||||
.header ===
|
||||
"string"
|
||||
? column
|
||||
.columnDef
|
||||
.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
{currentView === "machine" &&
|
||||
machineTable
|
||||
.getAllColumns()
|
||||
.some((column) =>
|
||||
column.getCanHide()
|
||||
) && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Columns className="mr-0 sm:mr-2 h-4 w-4" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("columns") ||
|
||||
"Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="w-48"
|
||||
>
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") ||
|
||||
"Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{machineTable
|
||||
.getAllColumns()
|
||||
.filter((column) =>
|
||||
column.getCanHide()
|
||||
)
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(
|
||||
value
|
||||
) =>
|
||||
column.toggleVisibility(
|
||||
!!value
|
||||
)
|
||||
}
|
||||
>
|
||||
{typeof column
|
||||
.columnDef
|
||||
.header ===
|
||||
"string"
|
||||
? column
|
||||
.columnDef
|
||||
.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -828,7 +761,8 @@ export default function ClientsTable({
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<TabsContent value="user">
|
||||
<Table>
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{userTable
|
||||
.getHeaderGroups()
|
||||
@@ -841,6 +775,15 @@ export default function ClientsTable({
|
||||
.map((header) => (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className={`whitespace-nowrap ${
|
||||
header.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: header.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
@@ -876,6 +819,15 @@ export default function ClientsTable({
|
||||
key={
|
||||
cell.id
|
||||
}
|
||||
className={`whitespace-nowrap ${
|
||||
cell.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: cell.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{flexRender(
|
||||
cell
|
||||
@@ -900,6 +852,7 @@ export default function ClientsTable({
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<DataTablePagination
|
||||
table={userTable}
|
||||
@@ -910,7 +863,8 @@ export default function ClientsTable({
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="machine">
|
||||
<Table>
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{machineTable
|
||||
.getHeaderGroups()
|
||||
@@ -923,6 +877,15 @@ export default function ClientsTable({
|
||||
.map((header) => (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className={`whitespace-nowrap ${
|
||||
header.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: header.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
@@ -958,6 +921,15 @@ export default function ClientsTable({
|
||||
key={
|
||||
cell.id
|
||||
}
|
||||
className={`whitespace-nowrap ${
|
||||
cell.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: cell.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{flexRender(
|
||||
cell
|
||||
@@ -982,6 +954,7 @@ export default function ClientsTable({
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<DataTablePagination
|
||||
table={machineTable}
|
||||
|
||||
@@ -33,6 +33,9 @@ export function DomainsDataTable<TData, TValue>({
|
||||
onAdd={onAdd}
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="baseDomain"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ export default function DomainsTable({ domains, orgId }: Props) {
|
||||
const columns: ColumnDef<DomainRow>[] = [
|
||||
{
|
||||
accessorKey: "baseDomain",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -209,13 +210,47 @@ export default function DomainsTable({ domains, orgId }: Props) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => <span className="p-3">{t("actions")}</span>,
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const domain = row.original;
|
||||
const isRestarting = restartingDomains.has(domain.domainId);
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
Open menu
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<Link
|
||||
className="block w-full"
|
||||
href={`/${orgId}/settings/domains/${domain.domainId}`}
|
||||
>
|
||||
<DropdownMenuItem>
|
||||
{t("viewSettings")}
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelectedDomain(domain);
|
||||
setIsDeleteModalOpen(true);
|
||||
}}
|
||||
>
|
||||
<span className="text-red-500">
|
||||
{t("delete")}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{domain.failed && (
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -240,41 +275,6 @@ export default function DomainsTable({ domains, orgId }: Props) {
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
Open menu
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<Link
|
||||
className="block w-full"
|
||||
href={`/${orgId}/settings/domains/${domain.domainId}`}
|
||||
>
|
||||
<DropdownMenuItem>
|
||||
{t("viewSettings")}
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setSelectedDomain(domain);
|
||||
setIsDeleteModalOpen(true);
|
||||
}}
|
||||
>
|
||||
<span className="text-red-500">
|
||||
{t("delete")}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
{/* <Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
|
||||
@@ -32,6 +32,9 @@ export function InvitationsDataTable<TData, TValue>({
|
||||
searchColumn="email"
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="email"
|
||||
stickyRightColumn="dots"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ export default function InvitationsTable({
|
||||
const columns: ColumnDef<InvitationRow>[] = [
|
||||
{
|
||||
accessorKey: "email",
|
||||
enableHiding: false,
|
||||
header: () => (<span className="p-3">{t("email")}</span>)
|
||||
},
|
||||
{
|
||||
@@ -91,6 +92,8 @@ export default function InvitationsTable({
|
||||
},
|
||||
{
|
||||
id: "dots",
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const invitation = row.original;
|
||||
return (
|
||||
@@ -119,13 +122,13 @@ export default function InvitationsTable({
|
||||
</DropdownMenu>
|
||||
|
||||
<Button
|
||||
variant={"secondary"}
|
||||
variant={"outline"}
|
||||
onClick={() => {
|
||||
setIsRegenerateModalOpen(true);
|
||||
setSelectedInvitation(invitation);
|
||||
}}
|
||||
>
|
||||
<span>{t("inviteRegenerate")}</span>
|
||||
{t("regenerate", { fallback: "Regenerate" })}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -33,6 +33,7 @@ export function LicenseKeysDataTable({
|
||||
const columns: ColumnDef<LicenseKeyCache>[] = [
|
||||
{
|
||||
accessorKey: "licenseKey",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -123,9 +124,10 @@ export function LicenseKeysDataTable({
|
||||
},
|
||||
{
|
||||
id: "delete",
|
||||
header: () => <span className="p-3">{t("actions")}</span>,
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<Button variant={"outline"}
|
||||
onClick={() => onDelete(row.original)}
|
||||
>
|
||||
@@ -146,6 +148,9 @@ export function LicenseKeysDataTable({
|
||||
searchColumn="licenseKey"
|
||||
onAdd={onCreate}
|
||||
addButtonText={t("licenseKeyAdd")}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="licenseKey"
|
||||
stickyRightColumn="delete"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ export function OrgApiKeysDataTable<TData, TValue>({
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
addButtonText={t('apiKeysAdd')}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="name"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ export default function OrgApiKeysTable({
|
||||
const columns: ColumnDef<OrgApiKeyRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -123,19 +124,12 @@ export default function OrgApiKeysTable({
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const r = row.original;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<Link href={`/${orgId}/settings/api-keys/${r.id}`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -167,6 +161,14 @@ export default function OrgApiKeysTable({
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link href={`/${orgId}/settings/api-keys/${r.id}`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ export function PolicyDataTable<TData, TValue>({
|
||||
searchColumn="orgId"
|
||||
addButtonText={t('orgPoliciesAdd')}
|
||||
onAdd={onAdd}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="orgId"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -37,34 +37,9 @@ interface Props {
|
||||
export default function PolicyTable({ policies, onDelete, onAdd, onEdit }: Props) {
|
||||
const t = useTranslations();
|
||||
const columns: ColumnDef<PolicyRow>[] = [
|
||||
{
|
||||
id: "dots",
|
||||
cell: ({ row }) => {
|
||||
const r = row.original;
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
<span className="sr-only">{t('openMenu')}</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
onDelete(r.orgId);
|
||||
}}
|
||||
>
|
||||
<span className="text-red-500">{t('delete')}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "orgId",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -135,14 +110,31 @@ export default function PolicyTable({ policies, onDelete, onAdd, onEdit }: Props
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t('actions')}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const policy = row.original;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
<span className="sr-only">{t('openMenu')}</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
onDelete(policy.orgId);
|
||||
}}
|
||||
>
|
||||
<span className="text-red-500">{t('delete')}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className="ml-2"
|
||||
onClick={() => onEdit(policy)}
|
||||
>
|
||||
{t('edit')}
|
||||
|
||||
@@ -586,6 +586,7 @@ export default function ResourcesTable({
|
||||
const proxyColumns: ColumnDef<ResourceRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -748,19 +749,59 @@ export default function ResourcesTable({
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => <span className="p-3">{t("actions")}</span>,
|
||||
enableHiding: false,
|
||||
header: ({ table }) => {
|
||||
const hasHideableColumns = table
|
||||
.getAllColumns()
|
||||
.some((column) => column.getCanHide());
|
||||
if (!hasHideableColumns) {
|
||||
return <span className="p-3"></span>;
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col items-end gap-1 p-3">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="h-7 w-7 p-0">
|
||||
<Columns className="h-4 w-4" />
|
||||
<span className="sr-only">
|
||||
{t("columns") || "Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") || "Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{table
|
||||
.getAllColumns()
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) =>
|
||||
column.toggleVisibility(!!value)
|
||||
}
|
||||
>
|
||||
{typeof column.columnDef.header ===
|
||||
"string"
|
||||
? column.columnDef.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const resourceRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href={`/${resourceRow.orgId}/settings/resources/${resourceRow.nice}`}
|
||||
>
|
||||
<Button variant={"outline"}>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -791,6 +832,14 @@ export default function ResourcesTable({
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link
|
||||
href={`/${resourceRow.orgId}/settings/resources/${resourceRow.nice}`}
|
||||
>
|
||||
<Button variant={"outline"}>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -800,6 +849,7 @@ export default function ResourcesTable({
|
||||
const internalColumns: ColumnDef<InternalResourceRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -902,20 +952,59 @@ export default function ResourcesTable({
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
header: () => <span className="p-3">{t("actions")}</span>,
|
||||
enableHiding: false,
|
||||
header: ({ table }) => {
|
||||
const hasHideableColumns = table
|
||||
.getAllColumns()
|
||||
.some((column) => column.getCanHide());
|
||||
if (!hasHideableColumns) {
|
||||
return <span className="p-3"></span>;
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col items-end gap-1 p-3">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="h-7 w-7 p-0">
|
||||
<Columns className="h-4 w-4" />
|
||||
<span className="sr-only">
|
||||
{t("columns") || "Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") || "Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{table
|
||||
.getAllColumns()
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) =>
|
||||
column.toggleVisibility(!!value)
|
||||
}
|
||||
>
|
||||
{typeof column.columnDef.header ===
|
||||
"string"
|
||||
? column.columnDef.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const resourceRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant={"outline"}
|
||||
onClick={() => {
|
||||
setEditingResource(resourceRow);
|
||||
setIsEditDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("edit")}
|
||||
</Button>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -940,6 +1029,15 @@ export default function ResourcesTable({
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
onClick={() => {
|
||||
setEditingResource(resourceRow);
|
||||
setIsEditDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("edit")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1090,122 +1188,6 @@ export default function ResourcesTable({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 sm:justify-end">
|
||||
{currentView === "proxy" &&
|
||||
proxyTable
|
||||
.getAllColumns()
|
||||
.some((column) =>
|
||||
column.getCanHide()
|
||||
) && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Columns className="mr-0 sm:mr-2 h-4 w-4" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("columns") ||
|
||||
"Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="w-48"
|
||||
>
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") ||
|
||||
"Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{proxyTable
|
||||
.getAllColumns()
|
||||
.filter((column) =>
|
||||
column.getCanHide()
|
||||
)
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(
|
||||
value
|
||||
) =>
|
||||
column.toggleVisibility(
|
||||
!!value
|
||||
)
|
||||
}
|
||||
>
|
||||
{typeof column
|
||||
.columnDef
|
||||
.header ===
|
||||
"string"
|
||||
? column
|
||||
.columnDef
|
||||
.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
{currentView === "internal" &&
|
||||
internalTable
|
||||
.getAllColumns()
|
||||
.some((column) =>
|
||||
column.getCanHide()
|
||||
) && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Columns className="mr-0 sm:mr-2 h-4 w-4" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("columns") ||
|
||||
"Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="w-48"
|
||||
>
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") ||
|
||||
"Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{internalTable
|
||||
.getAllColumns()
|
||||
.filter((column) =>
|
||||
column.getCanHide()
|
||||
)
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(
|
||||
value
|
||||
) =>
|
||||
column.toggleVisibility(
|
||||
!!value
|
||||
)
|
||||
}
|
||||
>
|
||||
{typeof column
|
||||
.columnDef
|
||||
.header ===
|
||||
"string"
|
||||
? column
|
||||
.columnDef
|
||||
.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -1225,7 +1207,8 @@ export default function ResourcesTable({
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<TabsContent value="proxy">
|
||||
<Table>
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{proxyTable
|
||||
.getHeaderGroups()
|
||||
@@ -1238,6 +1221,15 @@ export default function ResourcesTable({
|
||||
.map((header) => (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className={`whitespace-nowrap ${
|
||||
header.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: header.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
@@ -1273,6 +1265,15 @@ export default function ResourcesTable({
|
||||
key={
|
||||
cell.id
|
||||
}
|
||||
className={`whitespace-nowrap ${
|
||||
cell.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: cell.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{flexRender(
|
||||
cell
|
||||
@@ -1301,6 +1302,7 @@ export default function ResourcesTable({
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<DataTablePagination
|
||||
table={proxyTable}
|
||||
@@ -1311,7 +1313,8 @@ export default function ResourcesTable({
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="internal">
|
||||
<Table>
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{internalTable
|
||||
.getHeaderGroups()
|
||||
@@ -1324,6 +1327,15 @@ export default function ResourcesTable({
|
||||
.map((header) => (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className={`whitespace-nowrap ${
|
||||
header.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: header.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
@@ -1359,6 +1371,15 @@ export default function ResourcesTable({
|
||||
key={
|
||||
cell.id
|
||||
}
|
||||
className={`whitespace-nowrap ${
|
||||
cell.column.id ===
|
||||
"actions"
|
||||
? "sticky right-0 z-10 w-auto min-w-fit bg-card"
|
||||
: cell.column.id ===
|
||||
"name"
|
||||
? "md:sticky md:left-0 z-10 bg-card"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{flexRender(
|
||||
cell
|
||||
@@ -1387,6 +1408,7 @@ export default function ResourcesTable({
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<DataTablePagination
|
||||
table={internalTable}
|
||||
|
||||
@@ -36,6 +36,9 @@ export function RolesDataTable<TData, TValue>({
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
addButtonText={t('accessRolesAdd')}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="name"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
||||
const columns: ColumnDef<RoleRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -84,12 +85,13 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const roleRow = row.original;
|
||||
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<Button
|
||||
variant={"outline"}
|
||||
disabled={roleRow.isAdmin || false}
|
||||
|
||||
@@ -36,6 +36,9 @@ export function ShareLinksDataTable<TData, TValue>({
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
addButtonText={t('shareCreate')}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="resourceName"
|
||||
stickyRightColumn="delete"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ export default function ShareLinksTable({
|
||||
const columns: ColumnDef<ShareLinkRow>[] = [
|
||||
{
|
||||
accessorKey: "resourceName",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -254,11 +255,12 @@ export default function ShareLinksTable({
|
||||
},
|
||||
{
|
||||
id: "delete",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const resourceRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center space-x-2 justify-end">
|
||||
{/* <DropdownMenu> */}
|
||||
{/* <DropdownMenuTrigger asChild> */}
|
||||
{/* <Button variant="ghost" className="h-8 w-8 p-0"> */}
|
||||
|
||||
@@ -44,6 +44,8 @@ export function SitesDataTable<TData, TValue>({
|
||||
}}
|
||||
columnVisibility={columnVisibility}
|
||||
enableColumnVisibility={enableColumnVisibility}
|
||||
stickyLeftColumn="name"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
|
||||
const columns: ColumnDef<SiteRow>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -361,19 +362,12 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
|
||||
: []),
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const siteRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
|
||||
>
|
||||
<Button variant={"outline"}>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -402,6 +396,14 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link
|
||||
href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
|
||||
>
|
||||
<Button variant={"outline"}>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ export function UsersDataTable<TData, TValue>({
|
||||
onRefresh={onRefresh}
|
||||
isRefreshing={isRefreshing}
|
||||
addButtonText={t('accessUserCreate')}
|
||||
enableColumnVisibility={true}
|
||||
stickyLeftColumn="displayUsername"
|
||||
stickyRightColumn="actions"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
const columns: ColumnDef<UserRow>[] = [
|
||||
{
|
||||
accessorKey: "displayUsername",
|
||||
enableHiding: false,
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -133,9 +134,6 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
|
||||
return (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
{userRow.isOwner && (
|
||||
<Crown className="w-4 h-4 text-yellow-600" />
|
||||
)}
|
||||
<span>{userRow.role}</span>
|
||||
</div>
|
||||
);
|
||||
@@ -143,21 +141,58 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: () => (<span className="p-3">{t("actions")}</span>),
|
||||
enableHiding: false,
|
||||
header: () => <span className="p-3"></span>,
|
||||
cell: ({ row }) => {
|
||||
const userRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
{userRow.isOwner && (
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className="ml-2"
|
||||
disabled={true}
|
||||
>
|
||||
{t("manage")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
<div className="flex items-center justify-end">
|
||||
<div>
|
||||
{!userRow.isOwner && (
|
||||
<>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
{t("openMenu")}
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<Link
|
||||
href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
|
||||
className="block w-full"
|
||||
>
|
||||
<DropdownMenuItem>
|
||||
{t("accessUsersManage")}
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{`${userRow.username}-${userRow.idpId}` !==
|
||||
`${user?.username}-${user?.idpId}` && (
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setIsDeleteModalOpen(
|
||||
true
|
||||
);
|
||||
setSelectedUser(
|
||||
userRow
|
||||
);
|
||||
}}
|
||||
>
|
||||
<span className="text-red-500">
|
||||
{t("accessUserRemove")}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{!userRow.isOwner && (
|
||||
<Link
|
||||
href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
|
||||
@@ -172,59 +207,6 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<>
|
||||
<div>
|
||||
{userRow.isOwner && (
|
||||
<MoreHorizontal className="h-4 w-4 opacity-0" />
|
||||
)}
|
||||
{!userRow.isOwner && (
|
||||
<>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
{t("openMenu")}
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<Link
|
||||
href={`/${org?.org.orgId}/settings/access/users/${userRow.id}`}
|
||||
className="block w-full"
|
||||
>
|
||||
<DropdownMenuItem>
|
||||
{t("accessUsersManage")}
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{`${userRow.username}-${userRow.idpId}` !==
|
||||
`${user?.username}-${user?.idpId}` && (
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
setIsDeleteModalOpen(
|
||||
true
|
||||
);
|
||||
setSelectedUser(
|
||||
userRow
|
||||
);
|
||||
}}
|
||||
>
|
||||
<span className="text-red-500">
|
||||
{t(
|
||||
"accessUserRemove"
|
||||
)}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -273,9 +255,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
}}
|
||||
dialog={
|
||||
<div>
|
||||
<p>
|
||||
{t("userQuestionOrgRemove")}
|
||||
</p>
|
||||
<p>{t("userQuestionOrgRemove")}</p>
|
||||
<p>{t("userMessageOrgRemove")}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -121,16 +121,7 @@ export default function IdpTable({ idps, orgId }: Props) {
|
||||
cell: ({ row }) => {
|
||||
const siteRow = row.original;
|
||||
return (
|
||||
<div className="flex items-center justify-end">
|
||||
<Link href={`/${orgId}/settings/idp/${siteRow.idpId}/general`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className="ml-2"
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
@@ -161,6 +152,14 @@ export default function IdpTable({ idps, orgId }: Props) {
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Link href={`/${orgId}/settings/idp/${siteRow.idpId}/general`}>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
>
|
||||
{t("edit")}
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,6 +152,8 @@ type DataTableProps<TData, TValue> = {
|
||||
columnVisibility?: Record<string, boolean>;
|
||||
enableColumnVisibility?: boolean;
|
||||
persistColumnVisibility?: boolean | string;
|
||||
stickyLeftColumn?: string; // Column ID or accessorKey for left sticky column
|
||||
stickyRightColumn?: string; // Column ID or accessorKey for right sticky column (typically "actions")
|
||||
};
|
||||
|
||||
export function DataTable<TData, TValue>({
|
||||
@@ -171,7 +173,9 @@ export function DataTable<TData, TValue>({
|
||||
defaultPageSize = 20,
|
||||
columnVisibility: defaultColumnVisibility,
|
||||
enableColumnVisibility = false,
|
||||
persistColumnVisibility = false
|
||||
persistColumnVisibility = false,
|
||||
stickyLeftColumn,
|
||||
stickyRightColumn
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const t = useTranslations();
|
||||
|
||||
@@ -290,6 +294,28 @@ export function DataTable<TData, TValue>({
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to check if a column should be sticky
|
||||
const isStickyColumn = (columnId: string | undefined, accessorKey: string | undefined, position: "left" | "right"): boolean => {
|
||||
if (position === "left" && stickyLeftColumn) {
|
||||
return columnId === stickyLeftColumn || accessorKey === stickyLeftColumn;
|
||||
}
|
||||
if (position === "right" && stickyRightColumn) {
|
||||
return columnId === stickyRightColumn || accessorKey === stickyRightColumn;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Get sticky column classes
|
||||
const getStickyClasses = (columnId: string | undefined, accessorKey: string | undefined): string => {
|
||||
if (isStickyColumn(columnId, accessorKey, "left")) {
|
||||
return "md:sticky md:left-0 z-10 bg-card";
|
||||
}
|
||||
if (isStickyColumn(columnId, accessorKey, "right")) {
|
||||
return "sticky right-0 z-10 w-auto min-w-fit bg-card";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto max-w-12xl">
|
||||
<Card>
|
||||
@@ -329,131 +355,150 @@ export function DataTable<TData, TValue>({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 sm:justify-end">
|
||||
{enableColumnVisibility &&
|
||||
table
|
||||
.getAllColumns()
|
||||
.some((column) => column.getCanHide()) && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<Columns className="mr-0 sm:mr-2 h-4 w-4" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("columns") || "Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="w-48"
|
||||
>
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") || "Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{table
|
||||
.getAllColumns()
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) =>
|
||||
column.toggleVisibility(
|
||||
!!value
|
||||
)
|
||||
}
|
||||
>
|
||||
{typeof column.columnDef
|
||||
.header === "string"
|
||||
? column.columnDef
|
||||
.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
{onRefresh && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onRefresh}
|
||||
disabled={isRefreshing}
|
||||
>
|
||||
<RefreshCw
|
||||
className={`mr-0 sm:mr-2 h-4 w-4 ${isRefreshing ? "animate-spin" : ""}`}
|
||||
/>
|
||||
<span className="hidden sm:inline">
|
||||
{t("refresh")}
|
||||
</span>
|
||||
</Button>
|
||||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onRefresh}
|
||||
disabled={isRefreshing}
|
||||
>
|
||||
<RefreshCw
|
||||
className={`mr-0 sm:mr-2 h-4 w-4 ${isRefreshing ? "animate-spin" : ""}`}
|
||||
/>
|
||||
<span className="hidden sm:inline">
|
||||
{t("refresh")}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{onAdd && addButtonText && (
|
||||
<Button onClick={onAdd}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
{addButtonText}
|
||||
</Button>
|
||||
<div>
|
||||
<Button onClick={onAdd}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
{addButtonText}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className="whitespace-nowrap"
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef
|
||||
.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={
|
||||
row.getIsSelected() && "selected"
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className="whitespace-nowrap"
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
const columnId = header.column.id;
|
||||
const accessorKey = (header.column.columnDef as any).accessorKey as string | undefined;
|
||||
const stickyClasses = getStickyClasses(columnId, accessorKey);
|
||||
const isRightSticky = isStickyColumn(columnId, accessorKey, "right");
|
||||
const hasHideableColumns = enableColumnVisibility &&
|
||||
table.getAllColumns().some((col) => col.getCanHide());
|
||||
|
||||
return (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className={`whitespace-nowrap ${stickyClasses}`}
|
||||
>
|
||||
{header.isPlaceholder ? null : (
|
||||
isRightSticky && hasHideableColumns ? (
|
||||
<div className="flex flex-col items-end pr-3">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="h-7 w-7 p-0 mb-1">
|
||||
<Columns className="h-4 w-4" />
|
||||
<span className="sr-only">
|
||||
{t("columns") || "Columns"}
|
||||
</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
<DropdownMenuLabel>
|
||||
{t("toggleColumns") || "Toggle columns"}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{table
|
||||
.getAllColumns()
|
||||
.filter((column) => column.getCanHide())
|
||||
.map((column) => {
|
||||
return (
|
||||
<DropdownMenuCheckboxItem
|
||||
key={column.id}
|
||||
className="capitalize"
|
||||
checked={column.getIsVisible()}
|
||||
onCheckedChange={(value) =>
|
||||
column.toggleVisibility(!!value)
|
||||
}
|
||||
>
|
||||
{typeof column.columnDef.header === "string"
|
||||
? column.columnDef.header
|
||||
: column.id}
|
||||
</DropdownMenuCheckboxItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<div className="h-0 opacity-0 pointer-events-none overflow-hidden">
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)
|
||||
)
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results found.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={
|
||||
row.getIsSelected() && "selected"
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => {
|
||||
const columnId = cell.column.id;
|
||||
const accessorKey = (cell.column.columnDef as any).accessorKey as string | undefined;
|
||||
const stickyClasses = getStickyClasses(columnId, accessorKey);
|
||||
const isRightSticky = isStickyColumn(columnId, accessorKey, "right");
|
||||
return (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className={`whitespace-nowrap ${stickyClasses} ${isRightSticky ? "text-right" : ""}`}
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results found.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<DataTablePagination
|
||||
table={table}
|
||||
|
||||
Reference in New Issue
Block a user