@mdguggenbichler/slugbase-core 0.0.42 → 0.0.44
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/frontend/src/App.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { BrowserRouter, Routes, Route, Navigate, useLocation } from 'react-route
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
|
5
5
|
import { AppConfigProvider, useAppConfig } from './contexts/AppConfigContext';
|
|
6
|
-
import { PlanProvider } from './contexts/PlanContext';
|
|
6
|
+
import { PlanProvider, usePlan } from './contexts/PlanContext';
|
|
7
7
|
import { ToastProvider } from './components/ui/Toast';
|
|
8
8
|
import { TooltipProvider } from './components/ui/tooltip-base';
|
|
9
9
|
import Layout from './components/Layout';
|
|
@@ -50,6 +50,17 @@ function AdminRoute({ children }: { children: React.ReactNode }) {
|
|
|
50
50
|
return <>{children}</>;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** Redirect /admin to first visible admin tab (e.g. in cloud free plan, Users/Teams are hidden so redirect to ai or billing). */
|
|
54
|
+
function AdminIndexRedirect() {
|
|
55
|
+
const planInfo = usePlan();
|
|
56
|
+
const { extraAdminNavItems } = useAppConfig();
|
|
57
|
+
const showUsersAndTeams = !planInfo || planInfo.canShareWithTeams;
|
|
58
|
+
const firstPath = showUsersAndTeams
|
|
59
|
+
? 'members'
|
|
60
|
+
: (extraAdminNavItems?.[0]?.path ?? 'ai');
|
|
61
|
+
return <Navigate to={firstPath} replace />;
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
function SharedRedirect() {
|
|
54
65
|
const { pathPrefixForLinks } = useAppConfig();
|
|
55
66
|
const to = `${pathPrefixForLinks || ''}/bookmarks?scope=shared_with_me`.replace(/\/+/g, '/') || '/bookmarks?scope=shared_with_me';
|
|
@@ -122,7 +133,7 @@ function AppRoutes() {
|
|
|
122
133
|
<Route path="go-preferences" element={<GoPreferences />} />
|
|
123
134
|
<Route path="search-engine-guide" element={<SearchEngineGuide />} />
|
|
124
135
|
<Route path="admin" element={<AdminRoute><AdminLayout /></AdminRoute>}>
|
|
125
|
-
<Route index element={<
|
|
136
|
+
<Route index element={<AdminIndexRedirect />} />
|
|
126
137
|
<Route path="members" element={<AdminMembersPage />} />
|
|
127
138
|
<Route path="teams" element={<AdminTeamsPage />} />
|
|
128
139
|
{hideAdminOidcAndSmtp ? (
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
useSidebar,
|
|
31
31
|
} from './ui/sidebar';
|
|
32
32
|
import { useAppConfig } from '../contexts/AppConfigContext';
|
|
33
|
+
import { usePlan } from '../contexts/PlanContext';
|
|
33
34
|
import type { User } from '../contexts/AuthContext';
|
|
34
35
|
import { cn } from '../lib/utils';
|
|
35
36
|
|
|
@@ -45,6 +46,7 @@ export default function AppSidebar({ user, version = null }: AppSidebarProps) {
|
|
|
45
46
|
const location = useLocation();
|
|
46
47
|
const pathname = location.pathname;
|
|
47
48
|
const { appBasePath, pathPrefixForLinks, hideAdminOidcAndSmtp, extraAdminNavItems } = useAppConfig();
|
|
49
|
+
const planInfo = usePlan();
|
|
48
50
|
const { setOpenMobile, toggleSidebar, isMobile, state } = useSidebar();
|
|
49
51
|
const prefix = pathPrefixForLinks || '';
|
|
50
52
|
// For active matching use pathPrefixForLinks so it matches useLocation().pathname (e.g. when Router has basename="/app", pathname is "/bookmarks" not "/app/bookmarks").
|
|
@@ -52,9 +54,16 @@ export default function AppSidebar({ user, version = null }: AppSidebarProps) {
|
|
|
52
54
|
const adminBaseFull = `${pathBaseForActive}/admin`.replace(/\/+/g, '/') || '/admin';
|
|
53
55
|
const adminBaseLink = `${prefix}/admin`.replace(/\/+/g, '/') || '/admin';
|
|
54
56
|
|
|
57
|
+
// In cloud, show Users and Teams only on team plan; self-hosted (planInfo null) always shows them.
|
|
58
|
+
const showAdminUsersAndTeams = !planInfo || planInfo.canShareWithTeams;
|
|
59
|
+
|
|
55
60
|
const adminNavItems = [
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
...(showAdminUsersAndTeams
|
|
62
|
+
? [
|
|
63
|
+
{ pathForLink: `${adminBaseLink}/members`, pathForActive: `${adminBaseFull}/members`, label: t('admin.users'), icon: Users },
|
|
64
|
+
{ pathForLink: `${adminBaseLink}/teams`, pathForActive: `${adminBaseFull}/teams`, label: t('admin.teams'), icon: UserCog },
|
|
65
|
+
]
|
|
66
|
+
: []),
|
|
58
67
|
...(!hideAdminOidcAndSmtp
|
|
59
68
|
? [
|
|
60
69
|
{ pathForLink: `${adminBaseLink}/oidc`, pathForActive: `${adminBaseFull}/oidc`, label: t('admin.oidcProviders'), icon: Key },
|
|
@@ -52,7 +52,7 @@ export default function GlobalSearch() {
|
|
|
52
52
|
{ type: 'navigation', title: t('folders.title'), path: `${prefix}/folders`.replace(/\/+/g, '/') || '/folders', id: 'nav-folders' },
|
|
53
53
|
{ type: 'navigation', title: t('tags.title'), path: `${prefix}/tags`.replace(/\/+/g, '/') || '/tags', id: 'nav-tags' },
|
|
54
54
|
{ type: 'navigation', title: t('shared.title'), path: `${prefix}/shared`.replace(/\/+/g, '/') || '/shared', id: 'nav-shared' },
|
|
55
|
-
...(showAdmin ? [{ type: 'navigation' as const, title: t('admin.title'), path: `${prefix}/admin
|
|
55
|
+
...(showAdmin ? [{ type: 'navigation' as const, title: t('admin.title'), path: `${prefix}/admin`.replace(/\/+/g, '/') || '/admin', id: 'nav-admin' }] : []),
|
|
56
56
|
], [showAdmin, t, prefix]);
|
|
57
57
|
|
|
58
58
|
const actionItems: SearchResult[] = useMemo(() => [
|
|
@@ -67,7 +67,7 @@ export default function UserDropdown({ user }: UserDropdownProps) {
|
|
|
67
67
|
</DropdownMenuItem>
|
|
68
68
|
{showAdmin && (
|
|
69
69
|
<DropdownMenuItem asChild>
|
|
70
|
-
<Link to={`${prefix}/admin/
|
|
70
|
+
<Link to={`${prefix}/admin`.replace(/\/+/g, '/') || '/admin'} className="flex items-center gap-2 cursor-pointer">
|
|
71
71
|
<Settings className="h-4 w-4" />
|
|
72
72
|
{t('admin.title')}
|
|
73
73
|
</Link>
|