@orsetra/shared-ui 1.0.19 → 1.0.22
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.
|
@@ -5,7 +5,7 @@ import { usePathname } from "next/navigation"
|
|
|
5
5
|
import { MainSidebar, type SidebarMode } from "./sidebar/main-sidebar"
|
|
6
6
|
import { Sidebar, SidebarProvider, useSidebar } from "./sidebar/sidebar"
|
|
7
7
|
import { type SidebarMenus } from "./sidebar/data"
|
|
8
|
-
import { UserMenu, Button } from "../ui"
|
|
8
|
+
import { UserMenu, Button, type UserMenuConfig } from "../ui"
|
|
9
9
|
import { getMenuFromPath } from "../../lib/menu-utils"
|
|
10
10
|
import { useIsMobile } from "../../hooks/use-mobile"
|
|
11
11
|
import { Menu } from "lucide-react"
|
|
@@ -16,9 +16,10 @@ interface LayoutContainerProps {
|
|
|
16
16
|
user?: { profile?: { email?: string; preferred_username?: string } } | null
|
|
17
17
|
onSignOut?: () => void
|
|
18
18
|
mode?: SidebarMode
|
|
19
|
+
userMenuConfig?: UserMenuConfig
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
function LayoutContent({ children, sidebarMenus, user, onSignOut, mode = 'expanded' }: LayoutContainerProps) {
|
|
22
|
+
function LayoutContent({ children, sidebarMenus, user, onSignOut, mode = 'expanded', userMenuConfig }: LayoutContainerProps) {
|
|
22
23
|
const pathname = usePathname()
|
|
23
24
|
const { setOpen } = useSidebar()
|
|
24
25
|
const isMobile = useIsMobile()
|
|
@@ -96,7 +97,8 @@ function LayoutContent({ children, sidebarMenus, user, onSignOut, mode = 'expand
|
|
|
96
97
|
)}
|
|
97
98
|
<UserMenu
|
|
98
99
|
username={user?.profile?.email || user?.profile?.preferred_username}
|
|
99
|
-
onSignOut={onSignOut || (() => {})}
|
|
100
|
+
onSignOut={onSignOut || (() => {})}
|
|
101
|
+
menuConfig={userMenuConfig}
|
|
100
102
|
/>
|
|
101
103
|
</div>
|
|
102
104
|
</header>
|
package/components/ui/button.tsx
CHANGED
|
@@ -13,7 +13,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const base =
|
|
16
|
-
'inline-flex items-center justify-center font-semibold rounded-
|
|
16
|
+
'inline-flex items-center justify-center font-semibold rounded-none transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ibm-blue-60 focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none select-none'
|
|
17
17
|
|
|
18
18
|
export const variants: Record<ButtonVariant, string> = {
|
|
19
19
|
primary:
|
package/components/ui/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { Avatar, AvatarImage, AvatarFallback } from './avatar'
|
|
|
5
5
|
export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator } from './dropdown-menu'
|
|
6
6
|
export { Separator } from './separator'
|
|
7
7
|
export { Logo } from './logo'
|
|
8
|
-
export { UserMenu } from './user-menu'
|
|
8
|
+
export { UserMenu, type UserMenuItem, type UserMenuConfig } from './user-menu'
|
|
9
9
|
export { Input } from './input'
|
|
10
10
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './tooltip'
|
|
11
11
|
export { PageHeader } from './page-header'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/navigation"
|
|
4
|
-
import { LogOut,
|
|
4
|
+
import { LogOut, ChevronDown, type LucideIcon } from "lucide-react"
|
|
5
5
|
import Avatar from "react-avatar"
|
|
6
6
|
import { Button } from "./button"
|
|
7
7
|
import {
|
|
@@ -12,15 +12,30 @@ import {
|
|
|
12
12
|
DropdownMenuSeparator,
|
|
13
13
|
DropdownMenuTrigger,
|
|
14
14
|
} from "./dropdown-menu"
|
|
15
|
+
|
|
16
|
+
// Type for configurable user menu items
|
|
17
|
+
export interface UserMenuItem {
|
|
18
|
+
id: string
|
|
19
|
+
label: string
|
|
20
|
+
href: string
|
|
21
|
+
icon: LucideIcon
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UserMenuConfig {
|
|
25
|
+
items: UserMenuItem[]
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
interface UserMenuProps {
|
|
16
29
|
username?: string
|
|
17
30
|
onSignOut: () => void
|
|
31
|
+
menuConfig?: UserMenuConfig
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
export function UserMenu({ username, onSignOut }: UserMenuProps) {
|
|
34
|
+
export function UserMenu({ username, onSignOut, menuConfig }: UserMenuProps) {
|
|
21
35
|
const router = useRouter()
|
|
22
36
|
|
|
23
37
|
const displayName = username || "User"
|
|
38
|
+
const menuItems = menuConfig?.items || []
|
|
24
39
|
|
|
25
40
|
return (
|
|
26
41
|
<DropdownMenu>
|
|
@@ -50,28 +65,24 @@ export function UserMenu({ username, onSignOut }: UserMenuProps) {
|
|
|
50
65
|
<p className="text-sm font-medium leading-none">{displayName}</p>
|
|
51
66
|
</div>
|
|
52
67
|
</DropdownMenuLabel>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
>
|
|
72
|
-
<Settings className="mr-2 h-4 w-4" />
|
|
73
|
-
<span>Settings</span>
|
|
74
|
-
</DropdownMenuItem>
|
|
68
|
+
{menuItems.length > 0 && (
|
|
69
|
+
<>
|
|
70
|
+
<DropdownMenuSeparator />
|
|
71
|
+
{menuItems.map((item) => {
|
|
72
|
+
const Icon = item.icon
|
|
73
|
+
return (
|
|
74
|
+
<DropdownMenuItem
|
|
75
|
+
key={item.id}
|
|
76
|
+
className="cursor-pointer"
|
|
77
|
+
onClick={() => router.push(item.href)}
|
|
78
|
+
>
|
|
79
|
+
<Icon className="mr-2 h-4 w-4" />
|
|
80
|
+
<span>{item.label}</span>
|
|
81
|
+
</DropdownMenuItem>
|
|
82
|
+
)
|
|
83
|
+
})}
|
|
84
|
+
</>
|
|
85
|
+
)}
|
|
75
86
|
<DropdownMenuSeparator />
|
|
76
87
|
<DropdownMenuItem
|
|
77
88
|
className="cursor-pointer text-red-600 focus:text-red-600 focus:bg-red-50"
|
package/lib/base-service.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import HttpClient from './http-client';
|
|
1
|
+
import HttpClient, { type AuthHeadersProvider } from './http-client';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Classe de base pour tous les services qui utilisent HttpClient
|
|
5
|
-
* L'organization ID est automatiquement ajouté aux headers via les custom attributes AWS Amplify
|
|
6
5
|
*/
|
|
7
6
|
export abstract class BaseService {
|
|
8
7
|
protected httpClient: HttpClient;
|
|
9
8
|
|
|
10
|
-
constructor(baseUrl: string) {
|
|
11
|
-
this.httpClient = HttpClient.getInstance(baseUrl);
|
|
9
|
+
constructor(baseUrl: string, authHeadersProvider?: AuthHeadersProvider) {
|
|
10
|
+
this.httpClient = HttpClient.getInstance(baseUrl, authHeadersProvider);
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
protected handleServiceError(error: any): Error {
|
|
@@ -16,3 +15,5 @@ export abstract class BaseService {
|
|
|
16
15
|
return error
|
|
17
16
|
}
|
|
18
17
|
}
|
|
18
|
+
|
|
19
|
+
export type { AuthHeadersProvider };
|
package/lib/http-client.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
// Simplified HTTP client without AWS Amplify dependencies
|
|
2
2
|
|
|
3
|
+
export type AuthHeadersProvider = () => Promise<Record<string, string>> | Record<string, string>;
|
|
4
|
+
|
|
3
5
|
class HttpClient {
|
|
4
6
|
private baseUrl: string;
|
|
7
|
+
private authHeadersProvider?: AuthHeadersProvider;
|
|
5
8
|
|
|
6
|
-
private constructor(baseUrl: string) {
|
|
7
|
-
this.baseUrl = baseUrl ||
|
|
9
|
+
private constructor(baseUrl: string, authHeadersProvider?: AuthHeadersProvider) {
|
|
10
|
+
this.baseUrl = baseUrl || '';
|
|
11
|
+
this.authHeadersProvider = authHeadersProvider;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
public static getInstance(baseUrl: string): HttpClient {
|
|
11
|
-
return
|
|
14
|
+
public static getInstance(baseUrl: string, authHeadersProvider?: AuthHeadersProvider): HttpClient {
|
|
15
|
+
return new HttpClient(baseUrl, authHeadersProvider);
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
private getFullUrl(path: string): string {
|
|
@@ -20,15 +24,15 @@ class HttpClient {
|
|
|
20
24
|
const headers = new Headers();
|
|
21
25
|
headers.set('Content-Type', 'application/json');
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
if (this.authHeadersProvider) {
|
|
28
|
+
try {
|
|
29
|
+
const authHeaders = await this.authHeadersProvider();
|
|
30
|
+
Object.entries(authHeaders).forEach(([key, value]) => {
|
|
31
|
+
headers.set(key, value);
|
|
32
|
+
});
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.warn('Failed to get auth headers:', error);
|
|
35
|
+
}
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
return headers;
|
|
@@ -138,8 +142,8 @@ class HttpClient {
|
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
144
|
|
|
141
|
-
export function useHttpClient(baseUrl: string) {
|
|
142
|
-
return HttpClient.getInstance(baseUrl);
|
|
145
|
+
export function useHttpClient(baseUrl: string, authHeadersProvider?: AuthHeadersProvider) {
|
|
146
|
+
return HttpClient.getInstance(baseUrl, authHeadersProvider);
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
export default HttpClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orsetra/shared-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Shared UI components for Orsetra platform",
|
|
5
5
|
"main": "./index.ts",
|
|
6
6
|
"types": "./index.ts",
|
|
@@ -92,4 +92,4 @@
|
|
|
92
92
|
"next": "^16.0.7",
|
|
93
93
|
"typescript": "^5"
|
|
94
94
|
}
|
|
95
|
-
}
|
|
95
|
+
}
|