Refine shared shell, router, and service worker behavior
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* SettingsPage - Settings page component
|
||||
* Derived from Page component
|
||||
* Displays all settings fragment routes as panels
|
||||
* Platform default: lists registered fragment routes under the settings base path
|
||||
* and mounts each with {@code settingsFragmentPath} so fragments can resolve their own meta.
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
@@ -11,51 +11,21 @@ import { useRouter, useRoute } from '../components/Router.jsx';
|
||||
import { getRootItem } from '../../platform/menu.js';
|
||||
import { securityService, useSecurityState } from '../../security/runtime/security-service.js';
|
||||
|
||||
/**
|
||||
* SettingsPage Component
|
||||
* Settings page with icon and title
|
||||
* Queries Router for all routes under /settings and renders them as panels
|
||||
*/
|
||||
export function SettingsPage() {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const securityState = useSecurityState();
|
||||
|
||||
// Initialize search query from fragment path if we navigated via a fragment route
|
||||
const initialSearchQuery = useMemo(() => {
|
||||
if (route.fragment_path) {
|
||||
// Extract the last segment from fragment path (e.g., "general" from "/settings/general")
|
||||
const segments = route.fragment_path.split('/').filter(s => s.length > 0);
|
||||
if (segments.length > 1) {
|
||||
return segments[segments.length - 1]; // Return last segment
|
||||
}
|
||||
}
|
||||
return ''; // No fragment, show all
|
||||
}, [route.fragment_path]);
|
||||
|
||||
const [searchQuery, setSearchQuery] = React.useState(initialSearchQuery);
|
||||
|
||||
// Update search query when fragment path changes (e.g., navigating between fragments)
|
||||
React.useEffect(() => {
|
||||
setSearchQuery(initialSearchQuery);
|
||||
}, [initialSearchQuery]);
|
||||
|
||||
// Get the base path for this settings page (flexible - could be /settings, /config, etc.)
|
||||
const [searchQuery, setSearchQuery] = React.useState('');
|
||||
|
||||
const basePath = useMemo(() => {
|
||||
// Get current route path and extract the base (e.g., /settings from /settings/general)
|
||||
if (route.path) {
|
||||
// If it's a fragment route, use fragment_path, otherwise use path
|
||||
const currentPath = route.fragment_path || route.path;
|
||||
// Extract base path (first segment)
|
||||
const segments = currentPath.split('/').filter(s => s.length > 0);
|
||||
const segments = currentPath.split('/').filter((s) => s.length > 0);
|
||||
return segments.length > 0 ? `/${segments[0]}` : '/settings';
|
||||
}
|
||||
return '/settings'; // Default fallback
|
||||
return '/settings';
|
||||
}, [route.path, route.fragment_path]);
|
||||
|
||||
// Query Router for all routes under the base path
|
||||
// Depend on router.currentRoute to trigger recalculation when routes are registered
|
||||
// (currentRoute depends on routesVersion which changes when routes are registered)
|
||||
|
||||
const childRoutes = useMemo(() => {
|
||||
const allRoutes = router.getRoutes();
|
||||
const settingsRoot = getRootItem('settings');
|
||||
@@ -65,11 +35,9 @@ export function SettingsPage() {
|
||||
isPermitted: (rights, resourcePath, options = {}) => securityService.isPermitted(rights, resourcePath, options)
|
||||
};
|
||||
const routes = [];
|
||||
|
||||
// Find all routes that start with basePath but are not the basePath itself
|
||||
|
||||
for (const [path, routeData] of allRoutes.entries()) {
|
||||
if (path.startsWith(basePath + '/') && path !== basePath) {
|
||||
// Only include fragment routes
|
||||
if (path.startsWith(`${basePath}/`) && path !== basePath) {
|
||||
if (routeData.is_fragment) {
|
||||
const matchingMenuItem = settingsItems.find((item) => item.invoke_target === path);
|
||||
if (matchingMenuItem && !matchingMenuItem.isRenderable(security)) {
|
||||
@@ -83,56 +51,42 @@ export function SettingsPage() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by path for consistent ordering
|
||||
|
||||
routes.sort((a, b) => a.path.localeCompare(b.path));
|
||||
|
||||
return routes;
|
||||
}, [router, basePath, router.currentRoute, securityState]); // Include router.currentRoute to trigger when routes are registered
|
||||
|
||||
// Filter routes based on search query
|
||||
}, [router, basePath, router.currentRoute, securityState]);
|
||||
|
||||
const filteredRoutes = useMemo(() => {
|
||||
if (!searchQuery.trim()) {
|
||||
return childRoutes;
|
||||
}
|
||||
|
||||
const query = searchQuery.toLowerCase();
|
||||
return childRoutes.filter(route => {
|
||||
// Extract the last segment of the path as the route name
|
||||
const segments = route.path.split('/').filter(s => s.length > 0);
|
||||
return childRoutes.filter((r) => {
|
||||
const segments = r.path.split('/').filter((s) => s.length > 0);
|
||||
const routeName = segments[segments.length - 1] || '';
|
||||
return routeName.toLowerCase().includes(query);
|
||||
});
|
||||
}, [childRoutes, searchQuery]);
|
||||
|
||||
|
||||
return (
|
||||
<Page
|
||||
icon="settings"
|
||||
title="Settings"
|
||||
headerRight={[
|
||||
// Add buttons or controls here later
|
||||
]}
|
||||
>
|
||||
<Page icon="settings" title="Settings" headerRight={[]}>
|
||||
<YStack gap="$4" width="100%">
|
||||
{/* Search bar */}
|
||||
<Input
|
||||
placeholder="Search settings..."
|
||||
placeholder="Search settings…"
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
size="$4"
|
||||
/>
|
||||
|
||||
{/* Render all child route components */}
|
||||
{filteredRoutes.length > 0 ? (
|
||||
filteredRoutes.map((routeItem) => {
|
||||
const RouteComponent = routeItem.component;
|
||||
return (
|
||||
<RouteComponent key={routeItem.path} />
|
||||
<RouteComponent key={routeItem.path} settingsFragmentPath={routeItem.path} />
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Text fontSize="$4" color="$color" opacity={0.6}>
|
||||
{searchQuery ? 'No settings found matching your search.' : 'No settings available.'}
|
||||
<Text fontSize="$4" color="$textMuted">
|
||||
{searchQuery.trim() ? 'No settings found matching your search.' : 'No settings available.'}
|
||||
</Text>
|
||||
)}
|
||||
</YStack>
|
||||
|
||||
Reference in New Issue
Block a user