@arch-cadre/panel 1.0.6 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/actions/activity-log/index.cjs +1 -1
  2. package/dist/actions/activity-log/index.mjs +1 -1
  3. package/dist/actions/index.cjs +2 -2
  4. package/dist/actions/index.d.ts +2 -2
  5. package/dist/actions/index.mjs +2 -2
  6. package/dist/actions/profile.d.ts +1 -1
  7. package/dist/index.cjs +7 -7
  8. package/dist/index.mjs +7 -7
  9. package/dist/routes.cjs +10 -10
  10. package/dist/routes.mjs +10 -10
  11. package/dist/schema.cjs +1 -1
  12. package/dist/schema.d.ts +1 -1
  13. package/dist/schema.mjs +1 -1
  14. package/dist/ui/activity-log/components/ActivityStatsWidget.cjs +1 -1
  15. package/dist/ui/activity-log/components/ActivityStatsWidget.mjs +1 -1
  16. package/dist/ui/activity-log/components/RecentLogsWidget.cjs +1 -1
  17. package/dist/ui/activity-log/components/RecentLogsWidget.mjs +1 -1
  18. package/dist/ui/activity-log/pages/log-list.cjs +2 -2
  19. package/dist/ui/activity-log/pages/log-list.mjs +1 -1
  20. package/dist/ui/components/app-content.cjs +1 -1
  21. package/dist/ui/components/app-content.mjs +1 -1
  22. package/dist/ui/components/app-sidebar.cjs +3 -3
  23. package/dist/ui/components/app-sidebar.mjs +2 -2
  24. package/dist/ui/components/app-user.cjs +5 -5
  25. package/dist/ui/components/app-user.mjs +4 -4
  26. package/dist/ui/components/breadcrumb-slot.cjs +2 -2
  27. package/dist/ui/components/breadcrumb-slot.mjs +1 -1
  28. package/dist/ui/components/manager/module-card.cjs +3 -3
  29. package/dist/ui/components/manager/module-card.mjs +2 -2
  30. package/dist/ui/components/manager/module-list.cjs +3 -3
  31. package/dist/ui/components/manager/module-list.mjs +2 -2
  32. package/dist/ui/components/manager/module-upload.cjs +3 -3
  33. package/dist/ui/components/manager/module-upload.mjs +2 -2
  34. package/dist/ui/components/profile/components.cjs +7 -7
  35. package/dist/ui/components/profile/components.d.ts +1 -1
  36. package/dist/ui/components/profile/components.mjs +3 -3
  37. package/dist/ui/components/profile/link.cjs +2 -2
  38. package/dist/ui/components/profile/link.mjs +1 -1
  39. package/dist/ui/components/profile/page.cjs +2 -6
  40. package/dist/ui/components/profile/page.mjs +3 -10
  41. package/dist/ui/components/sidebar-slot.cjs +1 -1
  42. package/dist/ui/components/sidebar-slot.mjs +1 -1
  43. package/dist/ui/dashboard/page.cjs +3 -3
  44. package/dist/ui/dashboard/page.mjs +1 -1
  45. package/dist/ui/dashboard/widgets/WelcomeBackUserWidget.cjs +1 -0
  46. package/dist/ui/dashboard/widgets/WelcomeBackUserWidget.mjs +5 -4
  47. package/dist/ui/error.cjs +2 -2
  48. package/dist/ui/error.mjs +1 -1
  49. package/dist/ui/layout.cjs +3 -3
  50. package/dist/ui/layout.mjs +3 -3
  51. package/dist/ui/modules/docs/page.cjs +1 -1
  52. package/dist/ui/modules/docs/page.mjs +1 -1
  53. package/dist/ui/modules/page.cjs +3 -3
  54. package/dist/ui/modules/page.mjs +3 -3
  55. package/dist/ui/rbac/pages/rbac-admin.cjs +16 -16
  56. package/dist/ui/rbac/pages/rbac-admin.mjs +2 -2
  57. package/dist/ui/router.cjs +1 -1
  58. package/dist/ui/router.mjs +1 -1
  59. package/dist/ui/session-manager/components/sessions-list.cjs +7 -7
  60. package/dist/ui/session-manager/components/sessions-list.mjs +3 -3
  61. package/dist/ui/session-manager/pages/sessions-page.cjs +4 -4
  62. package/dist/ui/session-manager/pages/sessions-page.mjs +3 -3
  63. package/dist/ui/settings-page.cjs +3 -3
  64. package/dist/ui/settings-page.mjs +2 -2
  65. package/package.json +7 -6
  66. package/src/actions/actions.ts +17 -0
  67. package/src/actions/activity-log/index.ts +17 -0
  68. package/src/actions/index.ts +2 -0
  69. package/src/actions/manager.ts +168 -0
  70. package/src/actions/profile.ts +173 -0
  71. package/src/actions/rbac/index.ts +131 -0
  72. package/src/actions/session-manager/index.ts +87 -0
  73. package/src/actions/settings.ts +34 -0
  74. package/src/index.ts +135 -0
  75. package/src/intl.d.ts +9 -0
  76. package/src/navigation.ts +57 -0
  77. package/src/routes.ts +107 -0
  78. package/src/schema/activity-log.ts +16 -0
  79. package/src/schema.ts +1 -0
  80. package/src/types.ts +18 -0
  81. package/src/ui/activity-log/components/ActivityStatsWidget.tsx +37 -0
  82. package/src/ui/activity-log/components/RecentLogsWidget.tsx +74 -0
  83. package/src/ui/activity-log/pages/log-list.tsx +91 -0
  84. package/src/ui/components/app-content.tsx +51 -0
  85. package/src/ui/components/app-header.tsx +65 -0
  86. package/src/ui/components/app-sidebar.tsx +249 -0
  87. package/src/ui/components/app-user.tsx +126 -0
  88. package/src/ui/components/breadcrumb-slot.tsx +52 -0
  89. package/src/ui/components/manager/module-card.tsx +327 -0
  90. package/src/ui/components/manager/module-list.tsx +59 -0
  91. package/src/ui/components/manager/module-upload.tsx +84 -0
  92. package/src/ui/components/profile/components.tsx +311 -0
  93. package/src/ui/components/profile/link.tsx +36 -0
  94. package/src/ui/components/profile/page.tsx +45 -0
  95. package/src/ui/components/sidebar-slot.tsx +47 -0
  96. package/src/ui/dashboard/page.tsx +17 -0
  97. package/src/ui/dashboard/widgets/WelcomeBackUserWidget.tsx +47 -0
  98. package/src/ui/error.tsx +82 -0
  99. package/src/ui/layout.tsx +54 -0
  100. package/src/ui/modules/docs/page.tsx +105 -0
  101. package/src/ui/modules/page.tsx +30 -0
  102. package/src/ui/page.tsx +15 -0
  103. package/src/ui/rbac/pages/rbac-admin.tsx +551 -0
  104. package/src/ui/router.tsx +69 -0
  105. package/src/ui/session-manager/components/sessions-list.tsx +303 -0
  106. package/src/ui/session-manager/pages/sessions-page.tsx +22 -0
  107. package/src/ui/settings/page.tsx +73 -0
  108. package/src/ui/settings-page.tsx +97 -0
@@ -0,0 +1,249 @@
1
+ "use client";
2
+
3
+ import { useTranslation } from "@arch-cadre/intl";
4
+ import { Logo } from "@arch-cadre/ui/brand/logo";
5
+ import {
6
+ Collapsible,
7
+ CollapsibleContent,
8
+ CollapsibleTrigger,
9
+ } from "@arch-cadre/ui/components/collapsible";
10
+ import { ScrollArea } from "@arch-cadre/ui/components/scroll-area";
11
+ import {
12
+ Sidebar,
13
+ SidebarContent,
14
+ SidebarFooter,
15
+ SidebarGroup,
16
+ SidebarGroupLabel,
17
+ SidebarHeader,
18
+ SidebarMenu,
19
+ SidebarMenuButton,
20
+ SidebarMenuItem,
21
+ SidebarMenuSub,
22
+ SidebarMenuSubButton,
23
+ SidebarMenuSubItem,
24
+ useSidebar,
25
+ } from "@arch-cadre/ui/components/sidebar";
26
+ import { cn } from "@arch-cadre/ui/lib/utils";
27
+ import { Icon } from "@iconify/react";
28
+ import { ChevronRight } from "lucide-react";
29
+ import Link from "next/link";
30
+ import { usePathname } from "next/navigation";
31
+ import * as React from "react";
32
+ import { useEffect, useState } from "react";
33
+ import { AppUser } from "./app-user.js";
34
+
35
+ export type SidebarItem = {
36
+ id?: string;
37
+ title: string;
38
+ url: string;
39
+ icon?: string;
40
+ items?: SidebarItem[];
41
+ };
42
+
43
+ export type SidebarGroupType = {
44
+ title: string;
45
+ items: SidebarItem[];
46
+ };
47
+
48
+ export function AppSidebar({
49
+ isMain,
50
+ data,
51
+ ...props
52
+ }: React.ComponentProps<typeof Sidebar> & {
53
+ isMain: boolean;
54
+ data: SidebarGroupType[];
55
+ }) {
56
+ const { open, setOpenMobile, isMobile } = useSidebar();
57
+ const { t } = useTranslation();
58
+
59
+ const pathname = usePathname();
60
+ // state to track if scrolled
61
+ const [scrolled, setScrolledState] = useState(false);
62
+
63
+ // for exact path matching
64
+ const matchPath = (path: string) => {
65
+ return path === pathname;
66
+ };
67
+
68
+ // for parent paths
69
+ const matchPaths = (path: string) => {
70
+ return path === pathname || (path.length > 1 && pathname.startsWith(path));
71
+ };
72
+
73
+ // biome-ignore lint/correctness/useExhaustiveDependencies: <useExhaustiveDependencies>
74
+ useEffect(() => {
75
+ // close sidebar if mobile and route changed
76
+ if (isMobile && open) {
77
+ setOpenMobile(false);
78
+ }
79
+ }, [pathname]);
80
+
81
+ // handle scroll to add shadow to header/footer
82
+ const setScrolled = (e: React.UIEvent<HTMLDivElement>) => {
83
+ const scrollTop = e.currentTarget.scrollTop;
84
+
85
+ if (scrollTop > 20) {
86
+ setScrolledState(true);
87
+ } else {
88
+ setScrolledState(false);
89
+ }
90
+ };
91
+
92
+ return (
93
+ <Sidebar className="lg:border-r-0!" collapsible="offcanvas" {...props}>
94
+ <SidebarHeader className="hidden md:flex h-[var(--header-height)] py-0">
95
+ <div className="flex shrink-0 items-center px-4 h-[var(--header-height)] w-[var(--sidebar-width)] ">
96
+ <Link href="/kryo" className="items-center flex">
97
+ <Logo className="h-auto w-[134px]" aria-hidden={true} />
98
+ </Link>
99
+ </div>
100
+ </SidebarHeader>
101
+
102
+ <SidebarHeader
103
+ className={cn(
104
+ "px-2",
105
+ scrolled
106
+ ? "border-b border-border/50 shadow-[0_20px_20px_0px_rgb(246_246_246/90%)]"
107
+ : "",
108
+ )}
109
+ >
110
+ {isMain ? null : (
111
+ <SidebarMenuItem>
112
+ <SidebarMenuButton asChild>
113
+ <Link href="/kryo">
114
+ <span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
115
+ <Icon className="size-4" icon="solar:arrow-left-broken" />
116
+ </span>
117
+ <span>{t("Back to Dashboard")}</span>
118
+ </Link>
119
+ </SidebarMenuButton>
120
+ </SidebarMenuItem>
121
+ )}
122
+ </SidebarHeader>
123
+
124
+ <SidebarContent>
125
+ <ScrollArea
126
+ orientation="vertical"
127
+ className="h-full"
128
+ onScroll={(e) => setScrolled(e)}
129
+ >
130
+ {/* {isMain && (
131
+ <SidebarGroup className="group-data-[collapsible=icon]:hidden py-0">
132
+ <SidebarGroupLabel>General</SidebarGroupLabel>
133
+ <SidebarMenu>
134
+ <SidebarMenuItem>
135
+ <SidebarMenuButton
136
+ asChild
137
+ isActive={matchPaths("/dashboard")}
138
+ tooltip={t("sidebar.dashboard")}
139
+ >
140
+ <Link href="/dashboard">
141
+ <span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
142
+ <Icon className="size-4" icon="solar:home-2-broken" />
143
+ </span>
144
+ <span>{t("sidebar.dashboard")}</span>
145
+ </Link>
146
+ </SidebarMenuButton>
147
+ </SidebarMenuItem>
148
+ </SidebarMenu>
149
+ </SidebarGroup>
150
+ )} */}
151
+
152
+ {data.map((group) => (
153
+ <SidebarGroup
154
+ key={group.title}
155
+ className="group-data-[collapsible=icon]:hidden py-0"
156
+ >
157
+ <SidebarGroupLabel>{t(group.title as any)}</SidebarGroupLabel>
158
+
159
+ {group.items.map((item) => (
160
+ <SidebarMenu key={item.url}>
161
+ {item.items && item.items.length > 0 ? (
162
+ <Collapsible
163
+ key={item.url}
164
+ asChild
165
+ defaultOpen={matchPaths(item.url)}
166
+ className="group/collapsible"
167
+ >
168
+ <SidebarMenuItem>
169
+ <CollapsibleTrigger asChild>
170
+ <SidebarMenuButton
171
+ className="squircle"
172
+ isActive={matchPaths(item.url)}
173
+ tooltip={t(item.title as any)}
174
+ >
175
+ <span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
176
+ {item.icon && (
177
+ <Icon
178
+ className="size-4"
179
+ icon={item.icon as string}
180
+ />
181
+ )}
182
+ </span>
183
+
184
+ <span>{t(item.title as any)}</span>
185
+
186
+ <ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
187
+ </SidebarMenuButton>
188
+ </CollapsibleTrigger>
189
+
190
+ <CollapsibleContent>
191
+ <SidebarMenuSub>
192
+ {item.items?.map((subItem) => (
193
+ <SidebarMenuSubItem key={subItem.url}>
194
+ <SidebarMenuSubButton
195
+ isActive={matchPath(subItem.url)}
196
+ asChild
197
+ >
198
+ <Link href={subItem.url}>
199
+ <span>{t(subItem.title as any)}</span>
200
+ </Link>
201
+ </SidebarMenuSubButton>
202
+ </SidebarMenuSubItem>
203
+ ))}
204
+ </SidebarMenuSub>
205
+ </CollapsibleContent>
206
+ </SidebarMenuItem>
207
+ </Collapsible>
208
+ ) : (
209
+ <SidebarMenuItem key={item.url}>
210
+ <SidebarMenuButton
211
+ className="squircle"
212
+ asChild
213
+ isActive={matchPath(item.url)}
214
+ >
215
+ <Link href={item.url}>
216
+ <span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
217
+ {item.icon && (
218
+ <Icon
219
+ className="size-4"
220
+ icon={item.icon as string}
221
+ />
222
+ )}
223
+ </span>
224
+
225
+ <span>{t(item.title as any)}</span>
226
+ </Link>
227
+ </SidebarMenuButton>
228
+ </SidebarMenuItem>
229
+ )}
230
+ </SidebarMenu>
231
+ ))}
232
+ </SidebarGroup>
233
+ ))}
234
+ </ScrollArea>
235
+ </SidebarContent>
236
+
237
+ <SidebarFooter
238
+ className={cn(
239
+ "px-2",
240
+ scrolled
241
+ ? "border-t border-border/50 shadow-[0_-20px_20px_0px_rgb(246_246_246/90%)]"
242
+ : "",
243
+ )}
244
+ >
245
+ <AppUser />
246
+ </SidebarFooter>
247
+ </Sidebar>
248
+ );
249
+ }
@@ -0,0 +1,126 @@
1
+ "use client";
2
+
3
+ import { useTranslation } from "@arch-cadre/intl";
4
+ import { ExtensionPointClient } from "@arch-cadre/modules";
5
+ import {
6
+ Avatar,
7
+ AvatarFallback,
8
+ AvatarImage,
9
+ } from "@arch-cadre/ui/components/avatar";
10
+ import {
11
+ DropdownMenu,
12
+ DropdownMenuContent,
13
+ DropdownMenuGroup,
14
+ DropdownMenuItem,
15
+ DropdownMenuLabel,
16
+ DropdownMenuSeparator,
17
+ DropdownMenuTrigger,
18
+ } from "@arch-cadre/ui/components/dropdown-menu";
19
+ import {
20
+ SidebarMenu,
21
+ SidebarMenuButton,
22
+ SidebarMenuItem,
23
+ } from "@arch-cadre/ui/components/sidebar";
24
+ import { useIsMobile } from "@arch-cadre/ui/hooks/use-mobile";
25
+ import { useUser } from "@arch-cadre/ui/hooks/use-user";
26
+ import { cn } from "@arch-cadre/ui/lib/utils";
27
+ import { Icon } from "@iconify/react";
28
+ import * as React from "react";
29
+ import { toast } from "sonner";
30
+ import { logoutAction } from "../../actions/index.js";
31
+
32
+ export function AppUser() {
33
+ const { user, isLoading } = useUser();
34
+ const isMobile = useIsMobile();
35
+ const { t } = useTranslation();
36
+
37
+ if (!user) {
38
+ return;
39
+ }
40
+
41
+ const handleSignOut = async () => {
42
+ toast.promise(
43
+ async () => {
44
+ await logoutAction();
45
+ },
46
+ {
47
+ loading: t("Please wait..."),
48
+ success: t("Logout successful!"),
49
+ error: t("error_occurred"),
50
+ },
51
+ );
52
+ };
53
+
54
+ return (
55
+ <SidebarMenu>
56
+ <SidebarMenuItem>
57
+ <DropdownMenu>
58
+ <DropdownMenuTrigger asChild={true}>
59
+ <SidebarMenuButton
60
+ size="lg"
61
+ className={cn(
62
+ isLoading && "opacity-50",
63
+ "cursor-pointer squircle data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
64
+ )}
65
+ >
66
+ <Avatar className="h-8 w-8 rounded-full">
67
+ <AvatarImage src={user.image ?? undefined} alt={user.name} />
68
+ <AvatarFallback className="rounded-full">
69
+ {user.name.charAt(0).toUpperCase()}
70
+ </AvatarFallback>
71
+ </Avatar>
72
+ <div className="grid flex-1 text-left text-sm leading-tight">
73
+ <span className="truncate font-medium">{user.name}</span>
74
+ <span className="truncate text-xs">{user.email}</span>
75
+ </div>
76
+ {/*<ChevronsUpDown className="ml-auto size-4" />*/}
77
+ <Icon
78
+ icon="solar:menu-dots-broken"
79
+ aria-hidden="true"
80
+ className="mr-1 size-4 rotate-90"
81
+ />
82
+ </SidebarMenuButton>
83
+ </DropdownMenuTrigger>
84
+ <DropdownMenuContent
85
+ className="squircle w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
86
+ side={isMobile ? "bottom" : "top"}
87
+ align="end"
88
+ sideOffset={4}
89
+ >
90
+ <DropdownMenuLabel className="p-0 font-normal">
91
+ <div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
92
+ <Avatar className="h-8 w-8 rounded-full">
93
+ <AvatarImage src={user.image ?? undefined} alt={user.name} />
94
+ <AvatarFallback className="rounded-full">
95
+ {user.name.charAt(0).toUpperCase()}
96
+ </AvatarFallback>
97
+ </Avatar>
98
+ <div className="grid flex-1 text-left text-sm leading-tight">
99
+ <span className="truncate font-medium">{user.name}</span>
100
+ <span className="truncate text-xs">{user.email}</span>
101
+ </div>
102
+ </div>
103
+ </DropdownMenuLabel>
104
+
105
+ <ExtensionPointClient module="panel" point="app-user:extra-link" />
106
+
107
+ <DropdownMenuSeparator />
108
+
109
+ <button
110
+ type="button"
111
+ onClick={() => {
112
+ handleSignOut();
113
+ }}
114
+ className="w-full"
115
+ >
116
+ <DropdownMenuItem className="cursor-pointer">
117
+ <Icon icon="solar:logout-broken" />
118
+ {t("Logout")}
119
+ </DropdownMenuItem>
120
+ </button>
121
+ </DropdownMenuContent>
122
+ </DropdownMenu>
123
+ </SidebarMenuItem>
124
+ </SidebarMenu>
125
+ );
126
+ }
@@ -0,0 +1,52 @@
1
+ "use client";
2
+
3
+ import { useTranslation } from "@arch-cadre/intl";
4
+ import {
5
+ Breadcrumb,
6
+ BreadcrumbItem,
7
+ BreadcrumbList,
8
+ BreadcrumbPage,
9
+ BreadcrumbSeparator,
10
+ } from "@arch-cadre/ui/components/breadcrumb";
11
+ import {
12
+ Tooltip,
13
+ TooltipContent,
14
+ TooltipTrigger,
15
+ } from "@arch-cadre/ui/components/tooltip";
16
+ import Image from "next/image";
17
+ import Link from "next/link";
18
+ import * as React from "react";
19
+
20
+ export default function BreadcrumbSlot() {
21
+ const { t } = useTranslation();
22
+
23
+ return (
24
+ <Breadcrumb className="hidden sm:block">
25
+ <BreadcrumbList>
26
+ <BreadcrumbItem>
27
+ <Tooltip>
28
+ <TooltipTrigger asChild>
29
+ <Link href="/kryo">
30
+ <Image
31
+ width={16}
32
+ height={16}
33
+ src="/favicon.svg"
34
+ alt="logo"
35
+ className="size-4"
36
+ aria-hidden={true}
37
+ />
38
+ </Link>
39
+ </TooltipTrigger>
40
+ <TooltipContent>
41
+ <p>{t("Back to Dashboard")}</p>
42
+ </TooltipContent>
43
+ </Tooltip>
44
+ </BreadcrumbItem>
45
+ <BreadcrumbSeparator>&bull;</BreadcrumbSeparator>
46
+ <BreadcrumbItem>
47
+ <BreadcrumbPage>{t("Dashboard")}</BreadcrumbPage>
48
+ </BreadcrumbItem>
49
+ </BreadcrumbList>
50
+ </Breadcrumb>
51
+ );
52
+ }