@sybilion/uilib 1.2.0 → 1.2.3
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.
- package/dist/esm/components/ui/AppHeader/AppHeader.js +3 -3
- package/dist/esm/components/ui/Image/Image.styl.js +1 -1
- package/dist/esm/components/ui/NavUserHeader/NavUserHeader.js +28 -0
- package/dist/esm/components/ui/NavUserHeader/NavUserHeader.styl.js +7 -0
- package/dist/esm/components/ui/Page/AppShell/AppShell.styl.js +1 -1
- package/dist/esm/components/ui/Page/PageScroll/PageScroll.js +4 -4
- package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js +9 -9
- package/dist/esm/index.js +2 -1
- package/dist/esm/sybilion-auth/SybilionAuthProvider.js +30 -7
- package/dist/esm/sybilion-auth/exchangeSybilionToken.js +6 -2
- package/dist/esm/types/src/components/ui/AppHeader/AppHeader.d.ts +2 -1
- package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.d.ts +2 -0
- package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.types.d.ts +25 -0
- package/dist/esm/types/src/components/ui/NavUserHeader/index.d.ts +2 -0
- package/dist/esm/types/src/components/ui/Page/PageScroll/PageScroll.d.ts +2 -1
- package/dist/esm/types/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.d.ts +3 -1
- package/dist/esm/types/src/docs/pages/NavUserHeaderPage.d.ts +1 -0
- package/dist/esm/types/src/docs/pages/StandaloneAppLayoutPage.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +1 -0
- package/dist/esm/types/src/sybilion-auth/SybilionAuthProvider.d.ts +5 -2
- package/dist/esm/types/src/sybilion-auth/exchangeSybilionToken.d.ts +3 -1
- package/dist/esm/types/src/sybilion-auth/index.d.ts +1 -1
- package/docs/standalone-apps.md +266 -27
- package/package.json +6 -1
- package/src/components/ui/AppHeader/AppHeader.tsx +7 -3
- package/src/components/ui/Image/Image.styl +1 -0
- package/src/components/ui/NavUserHeader/NavUserHeader.styl +125 -0
- package/src/components/ui/NavUserHeader/NavUserHeader.styl.d.ts +28 -0
- package/src/components/ui/NavUserHeader/NavUserHeader.tsx +148 -0
- package/src/components/ui/NavUserHeader/NavUserHeader.types.ts +27 -0
- package/src/components/ui/NavUserHeader/avatar.svg +4 -0
- package/src/components/ui/NavUserHeader/index.ts +5 -0
- package/src/components/ui/Page/AppShell/AppShell.styl +1 -0
- package/src/components/ui/Page/PageScroll/PageScroll.tsx +9 -2
- package/src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.tsx +9 -0
- package/src/docs/pages/NavUserHeaderPage.tsx +89 -0
- package/src/docs/pages/StandaloneAppLayoutPage.styl +46 -0
- package/src/docs/pages/StandaloneAppLayoutPage.styl.d.ts +8 -0
- package/src/docs/pages/StandaloneAppLayoutPage.tsx +242 -0
- package/src/docs/pages/SybilionAuthProviderPage.tsx +5 -2
- package/src/docs/registry.ts +12 -0
- package/src/index.ts +1 -0
- package/src/sybilion-auth/SybilionAuthProvider.tsx +33 -11
- package/src/sybilion-auth/exchangeSybilionToken.ts +5 -1
- package/src/sybilion-auth/index.ts +1 -0
|
@@ -8,11 +8,11 @@ import { PAGE_HEADER_ID } from './appChromeAnchors.js';
|
|
|
8
8
|
function AppHeaderHost({ className, anchorId = PAGE_HEADER_ID, }) {
|
|
9
9
|
return jsx("header", { className: cn(S.root, className), id: anchorId });
|
|
10
10
|
}
|
|
11
|
-
function AppHeaderPortal({ children }) {
|
|
11
|
+
function AppHeaderPortal({ children, pageHeaderId = PAGE_HEADER_ID, }) {
|
|
12
12
|
const [container, setContainer] = useState(null);
|
|
13
13
|
useLayoutEffect(() => {
|
|
14
|
-
setContainer(document.getElementById(
|
|
15
|
-
}, []);
|
|
14
|
+
setContainer(document.getElementById(pageHeaderId));
|
|
15
|
+
}, [pageHeaderId]);
|
|
16
16
|
if (!container) {
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
2
|
|
|
3
|
-
var css_248z = ".Image_container__beG4N{display:inline-block;height:100%;position:relative;width:100%}.Image_image__Kkmwo{border-radius:inherit;display:block;height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.Image_image__Kkmwo.Image_loading__Hi33D{opacity:0}.Image_fallback__N1ndD{align-items:center;border-radius:inherit;display:flex;height:100%;justify-content:center;left:0;position:absolute;top:0;width:100%}";
|
|
3
|
+
var css_248z = ".Image_container__beG4N{background-color:var(--muted-50);display:inline-block;height:100%;position:relative;width:100%}.Image_image__Kkmwo{border-radius:inherit;display:block;height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.Image_image__Kkmwo.Image_loading__Hi33D{opacity:0}.Image_fallback__N1ndD{align-items:center;border-radius:inherit;display:flex;height:100%;justify-content:center;left:0;position:absolute;top:0;width:100%}";
|
|
4
4
|
var S = {"container":"Image_container__beG4N","image":"Image_image__Kkmwo","loading":"Image_loading__Hi33D","fallback":"Image_fallback__N1ndD"};
|
|
5
5
|
styleInject(css_248z);
|
|
6
6
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import cn from 'classnames';
|
|
3
|
+
import { UserCircleIcon, SunIcon, MoonIcon, SignOutIcon } from '@phosphor-icons/react';
|
|
4
|
+
import { ChevronDownIcon } from 'lucide-react';
|
|
5
|
+
import { Avatar } from '../Avatar/Avatar.js';
|
|
6
|
+
import { Button } from '../Button/Button.js';
|
|
7
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuItem } from '../DropdownMenu/DropdownMenu.js';
|
|
8
|
+
import { Image } from '../Image/Image.js';
|
|
9
|
+
import S from './NavUserHeader.styl.js';
|
|
10
|
+
|
|
11
|
+
function NavUserHeader({ variant = 'default', isLoading = false, isAuthenticated, user = null, menuItems, theme, onThemeToggle, onLogout, signInSlot, onSignInClick, }) {
|
|
12
|
+
const authenticated = isAuthenticated ?? true;
|
|
13
|
+
const avatarUrl = user?.avatar ?? '';
|
|
14
|
+
const userName = user?.name ?? '';
|
|
15
|
+
const userEmail = user?.email ?? '';
|
|
16
|
+
if (isLoading) {
|
|
17
|
+
return (jsxs(Button, { variant: "ghost", size: "sm", disabled: true, className: S.loadingButton, children: [jsx("div", { className: S.avatarSkeleton }), jsx("div", { className: S.textSkeleton })] }));
|
|
18
|
+
}
|
|
19
|
+
if (!authenticated) {
|
|
20
|
+
if (signInSlot) {
|
|
21
|
+
return signInSlot;
|
|
22
|
+
}
|
|
23
|
+
return (jsxs(Button, { variant: "ghost", size: "sm", className: S.loginButton, type: "button", onClick: onSignInClick, children: [jsx(UserCircleIcon, { className: S.iconLg }), jsx("span", { children: "Log in" })] }));
|
|
24
|
+
}
|
|
25
|
+
return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button, { variant: "ghost", size: "sm", className: cn(S.userButton, variant === 'compact' && S.compact), children: [jsx(Avatar, { className: S.avatar, children: jsx(Image, { url: avatarUrl, alt: userName, fallback: jsx("div", { className: S.avatarFallback }) }) }), variant === 'default' && (jsxs(Fragment, { children: [jsxs("div", { className: S.userInfo, children: [jsx("span", { className: `${S.userName} ph-no-capture`, children: userName }), jsx("span", { className: S.userEmail, children: userEmail })] }), jsx(ChevronDownIcon, { className: S.iconSm })] }))] }) }), jsxs(DropdownMenuContent, { className: S.dropdownContent, align: "end", elevation: "md", children: [jsx(DropdownMenuLabel, { className: S.userLabel, children: jsxs("div", { className: S.userLabelContent, children: [jsx(Avatar, { className: S.avatar, children: jsx(Image, { url: avatarUrl, alt: userName, fallback: jsx("div", { className: S.avatarFallback }) }) }), jsxs("div", { className: S.userDetails, children: [jsx("span", { className: `${S.userDetailName} ph-no-capture`, children: userName }), jsx("span", { className: S.userDetailEmail, children: userEmail })] })] }) }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuGroup, { children: [menuItems, onThemeToggle ? (jsx(DropdownMenuItem, { onSelect: () => onThemeToggle(), children: theme === 'dark' ? (jsxs(Fragment, { children: [jsx(SunIcon, {}), "Light theme"] })) : (jsxs(Fragment, { children: [jsx(MoonIcon, {}), "Dark theme"] })) })) : null] }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuItem, { variant: "destructive", onSelect: () => onLogout(), children: [jsx(SignOutIcon, {}), "Log out"] })] })] }));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { NavUserHeader };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import styleInject from 'style-inject';
|
|
2
|
+
|
|
3
|
+
var css_248z = ".NavUserHeader_loadingButton__UM1cm{gap:.5rem}.NavUserHeader_avatarSkeleton__bdWE3{border-radius:9999px;height:2rem;width:2rem}.NavUserHeader_avatarSkeleton__bdWE3,.NavUserHeader_textSkeleton__AOp9E{animation:NavUserHeader_pulse__GWYG6 2s cubic-bezier(.4,0,.6,1) infinite;background-color:var(--color-muted)}.NavUserHeader_textSkeleton__AOp9E{border-radius:.25rem;height:1rem;width:5rem}.NavUserHeader_loginButton__QA4q6{gap:.5rem}.NavUserHeader_iconLg__246wU{height:1.25rem;width:1.25rem}.NavUserHeader_iconSm__CWx2D{height:.75rem;width:.75rem}.NavUserHeader_menuIcon__u0VeA{height:1rem;margin-right:.5rem;width:1rem}.NavUserHeader_dropdownContent__djONy{width:14rem}.NavUserHeader_userButton__sBFb-{gap:.5rem;height:52px;padding:var(--p-2)}.NavUserHeader_userButton__sBFb-.NavUserHeader_compact__UfbAp{background-color:transparent!important;padding:0;transition:transform .2s ease-in-out}.NavUserHeader_userButton__sBFb-.NavUserHeader_compact__UfbAp:hover{transform:scale(1.1)}.NavUserHeader_avatar__Yksm-{height:2rem;width:2rem}.NavUserHeader_avatarImage__d6rzY{border-radius:inherit;height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.NavUserHeader_avatarFallback__TKi2T{background-color:var(--color-primary);background:url(avatar.svg) no-repeat 50%;border-radius:inherit;color:var(--color-primary-foreground);height:100%;width:100%}.NavUserHeader_userInfo__kReZ2{align-items:flex-start;display:flex;flex-direction:column;gap:.25rem;text-align:left}.NavUserHeader_userName__8xek-{font-size:var(--text-sm);font-weight:400;line-height:1;max-width:7.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.NavUserHeader_userEmail__HKdtn{color:var(--sb-slate-500);font-size:var(--text-xs);line-height:1}.NavUserHeader_userLabel__DAxki{font-weight:400;padding:0}.NavUserHeader_userLabelContent__n5ngd{align-items:center;display:flex;font-size:.875rem;gap:.5rem;padding:.5rem;text-align:left}.NavUserHeader_userDetails__5r-k8{display:grid;flex:1;font-size:.875rem;line-height:1.25;text-align:left}.NavUserHeader_userDetailName__EajCc{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.NavUserHeader_userDetailEmail__LsK5z{color:var(--color-muted-foreground);font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@keyframes NavUserHeader_pulse__GWYG6{0%,to{opacity:1}50%{opacity:.5}}";
|
|
4
|
+
var S = {"loadingButton":"NavUserHeader_loadingButton__UM1cm","avatarSkeleton":"NavUserHeader_avatarSkeleton__bdWE3","pulse":"NavUserHeader_pulse__GWYG6","textSkeleton":"NavUserHeader_textSkeleton__AOp9E","loginButton":"NavUserHeader_loginButton__QA4q6","iconLg":"NavUserHeader_iconLg__246wU","iconSm":"NavUserHeader_iconSm__CWx2D","menuIcon":"NavUserHeader_menuIcon__u0VeA","dropdownContent":"NavUserHeader_dropdownContent__djONy","userButton":"NavUserHeader_userButton__sBFb-","compact":"NavUserHeader_compact__UfbAp","avatar":"NavUserHeader_avatar__Yksm-","avatarImage":"NavUserHeader_avatarImage__d6rzY","avatarFallback":"NavUserHeader_avatarFallback__TKi2T","userInfo":"NavUserHeader_userInfo__kReZ2","userName":"NavUserHeader_userName__8xek-","userEmail":"NavUserHeader_userEmail__HKdtn","userLabel":"NavUserHeader_userLabel__DAxki","userLabelContent":"NavUserHeader_userLabelContent__n5ngd","userDetails":"NavUserHeader_userDetails__5r-k8","userDetailName":"NavUserHeader_userDetailName__EajCc","userDetailEmail":"NavUserHeader_userDetailEmail__LsK5z"};
|
|
5
|
+
styleInject(css_248z);
|
|
6
|
+
|
|
7
|
+
export { S as default };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
2
|
|
|
3
|
-
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.AppShell_root__ONlNK{display:grid;flex:1;grid-template-areas:\"main\";grid-template-columns:1fr;min-height:0;width:100%}@media (min-width:768px){.AppShell_root__ONlNK{grid-template-areas:\"sidebar main\";grid-template-columns:var(--sidebar-width) 1fr}[data-slot=sidebar-wrapper][data-state=collapsed] .AppShell_root__ONlNK{grid-template-columns:0 1fr}}.AppShell_mainColumn__Emn1p{display:flex;flex:1;flex-direction:column;grid-area:main;min-height:0;min-width:0}[data-slot=sidebar-wrapper][data-state=collapsed] .AppShell_mainColumn__Emn1p{margin-left:var(--p-3)}.AppShell_mainBody__IoVuy{background-color:var(--page-color);border-radius:var(--p-4);flex:1;min-width:0;padding-bottom:var(--page-y-padding)}";
|
|
3
|
+
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.AppShell_root__ONlNK{display:grid;flex:1;grid-template-areas:\"main\";grid-template-columns:1fr;min-height:0;min-height:100%;width:100%}@media (min-width:768px){.AppShell_root__ONlNK{grid-template-areas:\"sidebar main\";grid-template-columns:var(--sidebar-width) 1fr}[data-slot=sidebar-wrapper][data-state=collapsed] .AppShell_root__ONlNK{grid-template-columns:0 1fr}}.AppShell_mainColumn__Emn1p{display:flex;flex:1;flex-direction:column;grid-area:main;min-height:0;min-width:0}[data-slot=sidebar-wrapper][data-state=collapsed] .AppShell_mainColumn__Emn1p{margin-left:var(--p-3)}.AppShell_mainBody__IoVuy{background-color:var(--page-color);border-radius:var(--p-4);flex:1;min-width:0;padding-bottom:var(--page-y-padding)}";
|
|
4
4
|
var S = {"root":"AppShell_root__ONlNK","mainColumn":"AppShell_mainColumn__Emn1p","mainBody":"AppShell_mainBody__IoVuy"};
|
|
5
5
|
styleInject(css_248z);
|
|
6
6
|
|
|
@@ -6,7 +6,7 @@ import { PageContext } from '../pageContext.js';
|
|
|
6
6
|
import { Scroll } from '@homecode/ui';
|
|
7
7
|
import S from './PageScroll.styl.js';
|
|
8
8
|
|
|
9
|
-
function PageScrollInner({ className, children, }) {
|
|
9
|
+
function PageScrollInner({ className, rootClassName, children, }) {
|
|
10
10
|
// const { setIsScrolled } = useContext(PageContext);
|
|
11
11
|
// const prevScrollTop = useRef(0);
|
|
12
12
|
const location = useLocation();
|
|
@@ -25,13 +25,13 @@ function PageScrollInner({ className, children, }) {
|
|
|
25
25
|
// };
|
|
26
26
|
return (jsx(Scroll, { y: true,
|
|
27
27
|
// fadeSize="l"
|
|
28
|
-
offset: { y: { before: 120, after: 130 } }, className: S.root, autoHide: true, innerClassName: cn(S.inner, className), yScrollbarClassName: S.scrollbar, onInnerRef: el => {
|
|
28
|
+
offset: { y: { before: 120, after: 130 } }, className: cn(S.root, rootClassName), autoHide: true, innerClassName: cn(S.inner, className), yScrollbarClassName: S.scrollbar, onInnerRef: el => {
|
|
29
29
|
scrollInnerRef.current = el;
|
|
30
30
|
}, children: children }));
|
|
31
31
|
}
|
|
32
|
-
const PageScroll = ({ children, className, }) => {
|
|
32
|
+
const PageScroll = ({ children, className, rootClassName, }) => {
|
|
33
33
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
34
|
-
return (jsx(PageContext.Provider, { value: { isScrolled, setIsScrolled }, children: jsx(PageScrollInner, { className: className, children: children }) }));
|
|
34
|
+
return (jsx(PageContext.Provider, { value: { isScrolled, setIsScrolled }, children: jsx(PageScrollInner, { className: className, rootClassName: rootClassName, children: children }) }));
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export { PageScroll };
|
package/dist/esm/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js
CHANGED
|
@@ -6,7 +6,7 @@ import { PackageOpen, ChevronDown, ChevronRight } from 'lucide-react';
|
|
|
6
6
|
import S from './SidebarDatasetsItemsGrouped.styl.js';
|
|
7
7
|
import { groupSidebarDatasets } from './groupSidebarDatasets.js';
|
|
8
8
|
|
|
9
|
-
function SidebarDatasetsItemsGrouped({ groupBy, datasets, selectedDatasetId, onDatasetClick, defaultExpandedGroupNames, className, }) {
|
|
9
|
+
function SidebarDatasetsItemsGrouped({ groupBy, datasets, preItems, postItems, selectedDatasetId, onDatasetClick, defaultExpandedGroupNames, className, }) {
|
|
10
10
|
const grouped = useMemo(() => groupSidebarDatasets(datasets, groupBy), [datasets, groupBy]);
|
|
11
11
|
const [expanded, setExpanded] = useState(new Set());
|
|
12
12
|
useEffect(() => {
|
|
@@ -35,14 +35,14 @@ function SidebarDatasetsItemsGrouped({ groupBy, datasets, selectedDatasetId, onD
|
|
|
35
35
|
return next;
|
|
36
36
|
});
|
|
37
37
|
};
|
|
38
|
-
return (jsx(SidebarGroup, { className: className, children:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
return (jsx(SidebarGroup, { className: className, children: jsxs(SidebarMenu, { children: [preItems, grouped.map(([groupName, groupDatasets]) => {
|
|
39
|
+
const isExpanded = expanded.has(groupName);
|
|
40
|
+
const parentActive = groupDatasets.some(d => d.id === selectedDatasetId);
|
|
41
|
+
return (jsxs(SidebarMenuItem, { children: [jsxs(SidebarMenuButton, { type: "button", isActive: parentActive, onClick: () => toggleGroup(groupName), children: [jsx(PackageOpen, { strokeWidth: 1.5, size: 16 }), jsx(SmartTextTruncate, { children: groupName }), jsx("div", { className: S.chevronContainer, children: isExpanded ? (jsx(ChevronDown, { size: 12 })) : (jsx(ChevronRight, { size: 12 })) })] }), isExpanded && (jsxs(SidebarMenuSub, { className: S.subMenuContainer, children: [jsx("div", { className: S.subMenuBorder }), groupDatasets.map(dataset => (jsx(SidebarMenuSubItem, { className: S.subMenuItem, children: jsx(SidebarMenuSubButton, { href: `#dataset-${dataset.id}`, isActive: dataset.id === selectedDatasetId, onClick: e => {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
onDatasetClick?.(dataset.id);
|
|
44
|
+
}, children: jsx(SmartTextTruncate, { children: dataset.name }) }) }, dataset.id)))] }))] }, groupName));
|
|
45
|
+
}), postItems] }) }));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export { SidebarDatasetsItemsGrouped };
|
package/dist/esm/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { SybilionAuthProvider, createSybilionApiFetch, sybilionApiFetch, useSybilionApiFetch, useSybilionAuth } from './sybilion-auth/SybilionAuthProvider.js';
|
|
1
|
+
export { SybilionAuthProvider, createSybilionApiFetch, getSybilionApiOriginFromSdk, sybilionApiFetch, useSybilionApiFetch, useSybilionAuth } from './sybilion-auth/SybilionAuthProvider.js';
|
|
2
2
|
export { SYBILION_AUTH_LOGIN_PATH, normalizeApiBaseUrl } from './sybilion-auth/authPaths.js';
|
|
3
3
|
export { exchangeAuth0AccessTokenForSybilionJwt } from './sybilion-auth/exchangeSybilionToken.js';
|
|
4
4
|
export { ChatContext, ChatProvider, useChat, useChats, useChatsForDataset, useChatsForScopeId, useCurrentChat } from './contexts/chat-context.js';
|
|
@@ -42,6 +42,7 @@ export { LabelWithId } from './components/ui/LabelWithId/LabelWithId.js';
|
|
|
42
42
|
export { LegacyPlatformLink } from './components/ui/LegacyPlatformLink/LegacyPlatformLink.js';
|
|
43
43
|
export { Logo } from './components/ui/Logo/Logo.js';
|
|
44
44
|
export { MobileAdaptiveSelector } from './components/ui/MobileAdaptiveSelector/MobileAdaptiveSelector.js';
|
|
45
|
+
export { NavUserHeader } from './components/ui/NavUserHeader/NavUserHeader.js';
|
|
45
46
|
export { NumberControl } from './components/ui/NumberControl/NumberControl.js';
|
|
46
47
|
export { AppShell, AppShellMainContent } from './components/ui/Page/AppShell/AppShell.js';
|
|
47
48
|
export { PageHeader } from './components/ui/Page/PageHeader/PageHeader.js';
|
|
@@ -2,9 +2,30 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { Auth0Provider, useAuth0 } from '@auth0/auth0-react';
|
|
3
3
|
import { createContext, useContext, useMemo, useRef, useState, useCallback, useEffect } from 'react';
|
|
4
4
|
import { normalizeApiBaseUrl } from './authPaths.js';
|
|
5
|
-
import { exchangeAuth0AccessTokenForSybilionJwt } from './exchangeSybilionToken.js';
|
|
6
5
|
|
|
7
6
|
const DEFAULT_TOKEN_KEY = 'sybilion.standalone.jwt';
|
|
7
|
+
function sybilionJwtFromLoginResponse(body) {
|
|
8
|
+
const t = body.data?.token ?? body.token;
|
|
9
|
+
if (!t)
|
|
10
|
+
throw new Error('Sybilion auth: missing token in login response');
|
|
11
|
+
return t;
|
|
12
|
+
}
|
|
13
|
+
/** Origin (`scheme://host:port`) for paths like `/api/v1/...`; derived from SDK URL layout. */
|
|
14
|
+
function getSybilionApiOriginFromSdk(sdk) {
|
|
15
|
+
const loginUrl = sdk.http.buildUrl('/v1/auth/login');
|
|
16
|
+
try {
|
|
17
|
+
const baseHref = typeof window !== 'undefined' && window.location?.href
|
|
18
|
+
? window.location.href
|
|
19
|
+
: 'http://localhost/';
|
|
20
|
+
const u = new URL(loginUrl, baseHref);
|
|
21
|
+
if (!u.pathname.endsWith('/v1/auth/login'))
|
|
22
|
+
return '';
|
|
23
|
+
return u.origin;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
8
29
|
const SybilionAuthContext = createContext(null);
|
|
9
30
|
function useSybilionAuth() {
|
|
10
31
|
const v = useContext(SybilionAuthContext);
|
|
@@ -51,7 +72,7 @@ function writeLs(key, value) {
|
|
|
51
72
|
/* quota / blocked */
|
|
52
73
|
}
|
|
53
74
|
}
|
|
54
|
-
function InnerSybilionSession({ children,
|
|
75
|
+
function InnerSybilionSession({ children, sdk, storageKey, logoutReturnTo, }) {
|
|
55
76
|
const auth0 = useAuth0();
|
|
56
77
|
const auth0Ref = useRef(auth0);
|
|
57
78
|
auth0Ref.current = auth0;
|
|
@@ -71,6 +92,7 @@ function InnerSybilionSession({ children, apiBaseUrl, storageKey, logoutReturnTo
|
|
|
71
92
|
logoutParams: returnTo ? { returnTo } : undefined,
|
|
72
93
|
});
|
|
73
94
|
}, [persistToken, logoutReturnTo]);
|
|
95
|
+
const apiBaseUrl = useMemo(() => getSybilionApiOriginFromSdk(sdk), [sdk]);
|
|
74
96
|
useEffect(() => {
|
|
75
97
|
if (!auth0.isAuthenticated || !auth0.user?.sub) {
|
|
76
98
|
persistToken(null);
|
|
@@ -88,7 +110,8 @@ function InnerSybilionSession({ children, apiBaseUrl, storageKey, logoutReturnTo
|
|
|
88
110
|
setExchangeError(null);
|
|
89
111
|
try {
|
|
90
112
|
const access = await auth0Ref.current.getAccessTokenSilently();
|
|
91
|
-
const
|
|
113
|
+
const loginBody = await sdk.auth.loginWithAuth0Identity(access);
|
|
114
|
+
const jwt = sybilionJwtFromLoginResponse(loginBody);
|
|
92
115
|
if (cancelled)
|
|
93
116
|
return;
|
|
94
117
|
persistToken(jwt);
|
|
@@ -111,7 +134,7 @@ function InnerSybilionSession({ children, apiBaseUrl, storageKey, logoutReturnTo
|
|
|
111
134
|
cancelled = true;
|
|
112
135
|
};
|
|
113
136
|
}, [
|
|
114
|
-
|
|
137
|
+
sdk,
|
|
115
138
|
auth0.isAuthenticated,
|
|
116
139
|
auth0.user?.sub,
|
|
117
140
|
persistToken,
|
|
@@ -163,7 +186,7 @@ function InnerSybilionSession({ children, apiBaseUrl, storageKey, logoutReturnTo
|
|
|
163
186
|
]);
|
|
164
187
|
return (jsx(SybilionAuthContext.Provider, { value: value, children: children }));
|
|
165
188
|
}
|
|
166
|
-
function SybilionAuthProvider({ children,
|
|
189
|
+
function SybilionAuthProvider({ children, sdk, auth0Domain, auth0ClientId, redirectUri, authorizationParams, sybilionTokenStorageKey = DEFAULT_TOKEN_KEY, logoutReturnTo, }) {
|
|
167
190
|
const mergedAuthParams = useMemo(() => ({
|
|
168
191
|
redirect_uri: authorizationParams?.redirect_uri ?? redirectUri,
|
|
169
192
|
audience: authorizationParams?.audience ?? `https://${auth0Domain}/api/v2/`,
|
|
@@ -179,7 +202,7 @@ function SybilionAuthProvider({ children, apiBaseUrl, auth0Domain, auth0ClientId
|
|
|
179
202
|
const cookieOpts = typeof window !== 'undefined'
|
|
180
203
|
? { cookieDomain: window.location.hostname }
|
|
181
204
|
: {};
|
|
182
|
-
return (jsx(Auth0Provider, { domain: auth0Domain, clientId: auth0ClientId, authorizationParams: mergedAuthParams, cacheLocation: "localstorage", useRefreshTokens: true, ...cookieOpts, children: jsx(InnerSybilionSession, {
|
|
205
|
+
return (jsx(Auth0Provider, { domain: auth0Domain, clientId: auth0ClientId, authorizationParams: mergedAuthParams, cacheLocation: "localstorage", useRefreshTokens: true, ...cookieOpts, children: jsx(InnerSybilionSession, { sdk: sdk, storageKey: sybilionTokenStorageKey, logoutReturnTo: logoutReturnTo, children: children }) }));
|
|
183
206
|
}
|
|
184
207
|
|
|
185
|
-
export { SybilionAuthProvider, createSybilionApiFetch, sybilionApiFetch, useSybilionApiFetch, useSybilionAuth };
|
|
208
|
+
export { SybilionAuthProvider, createSybilionApiFetch, getSybilionApiOriginFromSdk, sybilionApiFetch, useSybilionApiFetch, useSybilionAuth };
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { normalizeApiBaseUrl, SYBILION_AUTH_LOGIN_PATH } from './authPaths.js';
|
|
2
2
|
|
|
3
|
+
/** Default API segment before `/v1/...`; matches {@link createSybilionSDK} default `apiPrefix`. */
|
|
4
|
+
const SYBILION_AUTH_API_PREFIX = '/api';
|
|
3
5
|
/** POST `{ identity: auth0AccessToken, type: 'auth0' }` → Sybilion API JWT string. */
|
|
4
|
-
async function exchangeAuth0AccessTokenForSybilionJwt(
|
|
6
|
+
async function exchangeAuth0AccessTokenForSybilionJwt(
|
|
7
|
+
/** API origin only (no trailing slash), same as SDK `baseUrl`. */
|
|
8
|
+
apiBaseUrl, auth0AccessToken) {
|
|
5
9
|
const base = normalizeApiBaseUrl(apiBaseUrl);
|
|
6
|
-
const res = await fetch(`${base}${SYBILION_AUTH_LOGIN_PATH}`, {
|
|
10
|
+
const res = await fetch(`${base}${SYBILION_AUTH_API_PREFIX}${SYBILION_AUTH_LOGIN_PATH}`, {
|
|
7
11
|
method: 'POST',
|
|
8
12
|
headers: {
|
|
9
13
|
Accept: 'application/json',
|
|
@@ -7,5 +7,6 @@ export type AppHeaderProps = {
|
|
|
7
7
|
export declare function AppHeaderHost({ className, anchorId, }: AppHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
export type AppHeaderPortalProps = {
|
|
9
9
|
children: ReactNode;
|
|
10
|
+
pageHeaderId?: string;
|
|
10
11
|
};
|
|
11
|
-
export declare function AppHeaderPortal({ children }: AppHeaderPortalProps): import("react").ReactPortal;
|
|
12
|
+
export declare function AppHeaderPortal({ children, pageHeaderId, }: AppHeaderPortalProps): import("react").ReactPortal;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { NavUserHeaderProps } from './NavUserHeader.types';
|
|
2
|
+
export declare function NavUserHeader({ variant, isLoading, isAuthenticated, user, menuItems, theme, onThemeToggle, onLogout, signInSlot, onSignInClick, }: NavUserHeaderProps): string | number | bigint | true | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode>> | import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type NavUserHeaderUser = {
|
|
3
|
+
name: string;
|
|
4
|
+
email: string;
|
|
5
|
+
/** Passed to avatar `Image` as `src`. */
|
|
6
|
+
avatar?: string;
|
|
7
|
+
};
|
|
8
|
+
export type NavUserHeaderProps = {
|
|
9
|
+
variant?: 'default' | 'compact';
|
|
10
|
+
isLoading?: boolean;
|
|
11
|
+
/** When false, signed-out branch is shown. Defaults to true when omitted. */
|
|
12
|
+
isAuthenticated?: boolean;
|
|
13
|
+
/** Present when authenticated: shown in trigger and dropdown label. */
|
|
14
|
+
user?: NavUserHeaderUser | null;
|
|
15
|
+
/** Rows inside the menu above theme toggle and logout. Use `DropdownMenuItem` nodes. */
|
|
16
|
+
menuItems?: ReactNode;
|
|
17
|
+
/** Current theme drives the toggle row label/icons. */
|
|
18
|
+
theme: 'light' | 'dark';
|
|
19
|
+
/** When set, renders the light/dark theme menu row. */
|
|
20
|
+
onThemeToggle?: () => void;
|
|
21
|
+
onLogout: () => void;
|
|
22
|
+
/** Replaces default “Log in” control when signed out. */
|
|
23
|
+
signInSlot?: ReactNode;
|
|
24
|
+
onSignInClick?: () => void;
|
|
25
|
+
};
|
|
@@ -2,10 +2,12 @@ import { type SidebarDatasetsItemsGroupBy, type SidebarDatasetsItemsGroupedDatas
|
|
|
2
2
|
export type SidebarDatasetsItemsGroupedProps = {
|
|
3
3
|
groupBy: SidebarDatasetsItemsGroupBy;
|
|
4
4
|
datasets: SidebarDatasetsItemsGroupedDataset[];
|
|
5
|
+
preItems?: React.ReactNode;
|
|
6
|
+
postItems?: React.ReactNode;
|
|
5
7
|
selectedDatasetId?: number;
|
|
6
8
|
onDatasetClick?: (datasetId: number) => void;
|
|
7
9
|
/** When omitted, all groups start expanded. */
|
|
8
10
|
defaultExpandedGroupNames?: string[];
|
|
9
11
|
className?: string;
|
|
10
12
|
};
|
|
11
|
-
export declare function SidebarDatasetsItemsGrouped({ groupBy, datasets, selectedDatasetId, onDatasetClick, defaultExpandedGroupNames, className, }: SidebarDatasetsItemsGroupedProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function SidebarDatasetsItemsGrouped({ groupBy, datasets, preItems, postItems, selectedDatasetId, onDatasetClick, defaultExpandedGroupNames, className, }: SidebarDatasetsItemsGroupedProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function NavUserHeaderPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function StandaloneAppLayoutPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -31,6 +31,7 @@ export * from './components/ui/LabelWithId';
|
|
|
31
31
|
export * from './components/ui/LegacyPlatformLink';
|
|
32
32
|
export * from './components/ui/Logo';
|
|
33
33
|
export * from './components/ui/MobileAdaptiveSelector';
|
|
34
|
+
export * from './components/ui/NavUserHeader';
|
|
34
35
|
export * from './components/ui/NumberControl';
|
|
35
36
|
export * from './components/ui/Page';
|
|
36
37
|
export * from './components/ui/Progress';
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type RedirectLoginOptions } from '@auth0/auth0-react';
|
|
2
|
+
import type { SybilionSDK } from '@sybilion/sdk';
|
|
2
3
|
import type { JSX, ReactNode } from 'react';
|
|
4
|
+
/** Origin (`scheme://host:port`) for paths like `/api/v1/...`; derived from SDK URL layout. */
|
|
5
|
+
export declare function getSybilionApiOriginFromSdk(sdk: SybilionSDK): string;
|
|
3
6
|
export type SybilionAuthProviderProps = {
|
|
4
7
|
children: ReactNode;
|
|
5
|
-
|
|
8
|
+
sdk: SybilionSDK;
|
|
6
9
|
auth0Domain: string;
|
|
7
10
|
auth0ClientId: string;
|
|
8
11
|
redirectUri: string;
|
|
@@ -36,4 +39,4 @@ export declare function sybilionApiFetch(apiBaseUrl: string, bearerToken: string
|
|
|
36
39
|
export declare function createSybilionApiFetch(apiBaseUrl: string, getSybilionAccessToken: () => Promise<string | null>): (path: string, init?: RequestInit) => Promise<Response>;
|
|
37
40
|
/** Authenticated fetch using {@link useSybilionAuth} context. */
|
|
38
41
|
export declare function useSybilionApiFetch(): (path: string, init?: RequestInit) => Promise<Response>;
|
|
39
|
-
export declare function SybilionAuthProvider({ children,
|
|
42
|
+
export declare function SybilionAuthProvider({ children, sdk, auth0Domain, auth0ClientId, redirectUri, authorizationParams, sybilionTokenStorageKey, logoutReturnTo, }: SybilionAuthProviderProps): JSX.Element;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
/** POST `{ identity: auth0AccessToken, type: 'auth0' }` → Sybilion API JWT string. */
|
|
2
|
-
export declare function exchangeAuth0AccessTokenForSybilionJwt(
|
|
2
|
+
export declare function exchangeAuth0AccessTokenForSybilionJwt(
|
|
3
|
+
/** API origin only (no trailing slash), same as SDK `baseUrl`. */
|
|
4
|
+
apiBaseUrl: string, auth0AccessToken: string): Promise<string>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export type { SybilionAuthProviderProps, SybilionAuthContextValue, } from '#uilib/sybilion-auth/SybilionAuthProvider';
|
|
2
|
-
export { SybilionAuthProvider, useSybilionAuth, sybilionApiFetch, createSybilionApiFetch, useSybilionApiFetch, } from '#uilib/sybilion-auth/SybilionAuthProvider';
|
|
2
|
+
export { SybilionAuthProvider, getSybilionApiOriginFromSdk, useSybilionAuth, sybilionApiFetch, createSybilionApiFetch, useSybilionApiFetch, } from '#uilib/sybilion-auth/SybilionAuthProvider';
|
|
3
3
|
export { SYBILION_AUTH_LOGIN_PATH, normalizeApiBaseUrl, } from '#uilib/sybilion-auth/authPaths';
|
|
4
4
|
export { exchangeAuth0AccessTokenForSybilionJwt } from '#uilib/sybilion-auth/exchangeSybilionToken';
|