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