mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-31 05:59:26 +02:00
feat: Update Settings nomenclature and add tiered content collections
- Rename 'Models Manager' to 'AI Model Manager' - Rename 'ZIM Manager' to 'Content Manager' - Rename 'ZIM Remote Explorer' to 'Content Explorer' - Rename 'Curated ZIM Collections' to 'Curated Content Collections' - Add tiered category collections (Essential/Standard/Comprehensive) to Content Explorer, matching the Easy Setup Wizard Step 3 for consistency - Reorganize Settings sidebar alphabetically Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
42a18c8dc6
commit
b94deef437
|
|
@ -16,11 +16,13 @@ import StyledSidebar from '~/components/StyledSidebar'
|
||||||
import { getServiceLink } from '~/lib/navigation'
|
import { getServiceLink } from '~/lib/navigation'
|
||||||
|
|
||||||
const navigation = [
|
const navigation = [
|
||||||
|
{ name: 'AI Model Manager', href: '/settings/models', icon: IconDatabaseStar, current: false },
|
||||||
{ name: 'Apps', href: '/settings/apps', icon: CommandLineIcon, current: false },
|
{ name: 'Apps', href: '/settings/apps', icon: CommandLineIcon, current: false },
|
||||||
{ name: 'Benchmark', href: '/settings/benchmark', icon: ChartBarIcon, current: false },
|
{ name: 'Benchmark', href: '/settings/benchmark', icon: ChartBarIcon, current: false },
|
||||||
|
{ name: 'Content Explorer', href: '/settings/zim/remote-explorer', icon: MagnifyingGlassIcon, current: false },
|
||||||
|
{ name: 'Content Manager', href: '/settings/zim', icon: FolderIcon, current: false },
|
||||||
{ name: 'Legal Notices', href: '/settings/legal', icon: IconGavel, current: false },
|
{ name: 'Legal Notices', href: '/settings/legal', icon: IconGavel, current: false },
|
||||||
{ name: 'Maps Manager', href: '/settings/maps', icon: IconMapRoute, current: false },
|
{ name: 'Maps Manager', href: '/settings/maps', icon: IconMapRoute, current: false },
|
||||||
{ name: 'Models Manager', href: '/settings/models', icon: IconDatabaseStar, current: false },
|
|
||||||
{
|
{
|
||||||
name: 'Service Logs & Metrics',
|
name: 'Service Logs & Metrics',
|
||||||
href: getServiceLink('9999'),
|
href: getServiceLink('9999'),
|
||||||
|
|
@ -28,13 +30,6 @@ const navigation = [
|
||||||
current: false,
|
current: false,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
},
|
},
|
||||||
{ name: 'ZIM Manager', href: '/settings/zim', icon: FolderIcon, current: false },
|
|
||||||
{
|
|
||||||
name: 'Zim Remote Explorer',
|
|
||||||
href: '/settings/zim/remote-explorer',
|
|
||||||
icon: MagnifyingGlassIcon,
|
|
||||||
current: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Check for Updates',
|
name: 'Check for Updates',
|
||||||
href: '/settings/update',
|
href: '/settings/update',
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,10 @@ export default function ModelsPage(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
<Head title="App Settings" />
|
<Head title="AI Model Manager | Project N.O.M.A.D." />
|
||||||
<div className="xl:pl-72 w-full">
|
<div className="xl:pl-72 w-full">
|
||||||
<main className="px-12 py-6">
|
<main className="px-12 py-6">
|
||||||
<h1 className="text-4xl font-semibold mb-4">Models</h1>
|
<h1 className="text-4xl font-semibold mb-4">AI Model Manager</h1>
|
||||||
<p className="text-gray-500 mb-4">
|
<p className="text-gray-500 mb-4">
|
||||||
Easily manage the AI models available for Open WebUI. We recommend starting with smaller
|
Easily manage the AI models available for Open WebUI. We recommend starting with smaller
|
||||||
models first to see how they perform on your system before moving on to larger ones.
|
models first to see how they perform on your system before moving on to larger ones.
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,14 @@ export default function ZimPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
<Head title="ZIM Manager | Project N.O.M.A.D." />
|
<Head title="Content Manager | Project N.O.M.A.D." />
|
||||||
<div className="xl:pl-72 w-full">
|
<div className="xl:pl-72 w-full">
|
||||||
<main className="px-12 py-6">
|
<main className="px-12 py-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<h1 className="text-4xl font-semibold mb-2">ZIM Manager</h1>
|
<h1 className="text-4xl font-semibold mb-2">Content Manager</h1>
|
||||||
<p className="text-gray-500">
|
<p className="text-gray-500">
|
||||||
Manage your stored ZIM files.
|
Manage your stored content files.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,32 @@ import Input from '~/components/inputs/Input'
|
||||||
import { IconSearch } from '@tabler/icons-react'
|
import { IconSearch } from '@tabler/icons-react'
|
||||||
import useDebounce from '~/hooks/useDebounce'
|
import useDebounce from '~/hooks/useDebounce'
|
||||||
import CuratedCollectionCard from '~/components/CuratedCollectionCard'
|
import CuratedCollectionCard from '~/components/CuratedCollectionCard'
|
||||||
|
import CategoryCard from '~/components/CategoryCard'
|
||||||
|
import TierSelectionModal from '~/components/TierSelectionModal'
|
||||||
import StyledSectionHeader from '~/components/StyledSectionHeader'
|
import StyledSectionHeader from '~/components/StyledSectionHeader'
|
||||||
import { CuratedCollectionWithStatus } from '../../../../types/downloads'
|
import {
|
||||||
|
CuratedCollectionWithStatus,
|
||||||
|
CuratedCategory,
|
||||||
|
CategoryTier,
|
||||||
|
CategoryResource,
|
||||||
|
} from '../../../../types/downloads'
|
||||||
import useDownloads from '~/hooks/useDownloads'
|
import useDownloads from '~/hooks/useDownloads'
|
||||||
import ActiveDownloads from '~/components/ActiveDownloads'
|
import ActiveDownloads from '~/components/ActiveDownloads'
|
||||||
|
|
||||||
const CURATED_COLLECTIONS_KEY = 'curated-zim-collections'
|
const CURATED_COLLECTIONS_KEY = 'curated-zim-collections'
|
||||||
|
const CURATED_CATEGORIES_KEY = 'curated-categories'
|
||||||
|
|
||||||
|
// Helper to get all resources for a tier (including inherited resources)
|
||||||
|
const getAllResourcesForTier = (tier: CategoryTier, allTiers: CategoryTier[]): CategoryResource[] => {
|
||||||
|
const resources = [...tier.resources]
|
||||||
|
if (tier.includesTier) {
|
||||||
|
const includedTier = allTiers.find((t) => t.slug === tier.includesTier)
|
||||||
|
if (includedTier) {
|
||||||
|
resources.unshift(...getAllResourcesForTier(includedTier, allTiers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
|
||||||
export default function ZimRemoteExplorer() {
|
export default function ZimRemoteExplorer() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
@ -44,6 +64,10 @@ export default function ZimRemoteExplorer() {
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('')
|
||||||
const [queryUI, setQueryUI] = useState('')
|
const [queryUI, setQueryUI] = useState('')
|
||||||
|
|
||||||
|
// Category/tier selection state
|
||||||
|
const [tierModalOpen, setTierModalOpen] = useState(false)
|
||||||
|
const [activeCategory, setActiveCategory] = useState<CuratedCategory | null>(null)
|
||||||
|
|
||||||
const debouncedSetQuery = debounce((val: string) => {
|
const debouncedSetQuery = debounce((val: string) => {
|
||||||
setQuery(val)
|
setQuery(val)
|
||||||
}, 400)
|
}, 400)
|
||||||
|
|
@ -54,6 +78,13 @@ export default function ZimRemoteExplorer() {
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Fetch curated categories with tiers
|
||||||
|
const { data: categories } = useQuery({
|
||||||
|
queryKey: [CURATED_CATEGORIES_KEY],
|
||||||
|
queryFn: () => api.listCuratedCategories(),
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
})
|
||||||
|
|
||||||
const { data: downloads, invalidate: invalidateDownloads } = useDownloads({
|
const { data: downloads, invalidate: invalidateDownloads } = useDownloads({
|
||||||
filetype: 'zim',
|
filetype: 'zim',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
@ -180,6 +211,43 @@ export default function ZimRemoteExplorer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Category/tier handlers
|
||||||
|
const handleCategoryClick = (category: CuratedCategory) => {
|
||||||
|
if (!isOnline) return
|
||||||
|
setActiveCategory(category)
|
||||||
|
setTierModalOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTierSelect = async (category: CuratedCategory, tier: CategoryTier) => {
|
||||||
|
// Get all resources for this tier (including inherited ones)
|
||||||
|
const resources = getAllResourcesForTier(tier, category.tiers)
|
||||||
|
|
||||||
|
// Download each resource
|
||||||
|
try {
|
||||||
|
for (const resource of resources) {
|
||||||
|
await api.downloadRemoteZimFile(resource.url)
|
||||||
|
}
|
||||||
|
addNotification({
|
||||||
|
message: `Started downloading ${resources.length} files from "${category.name} - ${tier.name}"`,
|
||||||
|
type: 'success',
|
||||||
|
})
|
||||||
|
invalidateDownloads()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading tier resources:', error)
|
||||||
|
addNotification({
|
||||||
|
message: 'An error occurred while starting downloads.',
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
closeTierModal()
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeTierModal = () => {
|
||||||
|
setTierModalOpen(false)
|
||||||
|
setActiveCategory(null)
|
||||||
|
}
|
||||||
|
|
||||||
const fetchLatestCollections = useMutation({
|
const fetchLatestCollections = useMutation({
|
||||||
mutationFn: () => api.fetchLatestZimCollections(),
|
mutationFn: () => api.fetchLatestZimCollections(),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
|
|
@ -200,13 +268,13 @@ export default function ZimRemoteExplorer() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
<Head title="ZIM Remote Explorer | Project N.O.M.A.D." />
|
<Head title="Content Explorer | Project N.O.M.A.D." />
|
||||||
<div className="xl:pl-72 w-full">
|
<div className="xl:pl-72 w-full">
|
||||||
<main className="px-12 py-6">
|
<main className="px-12 py-6">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<h1 className="text-4xl font-semibold mb-2">ZIM Remote Explorer</h1>
|
<h1 className="text-4xl font-semibold mb-2">Content Explorer</h1>
|
||||||
<p className="text-gray-500">Browse and download ZIM files for offline reading!</p>
|
<p className="text-gray-500">Browse and download content for offline reading!</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!isOnline && (
|
{!isOnline && (
|
||||||
|
|
@ -220,13 +288,13 @@ export default function ZimRemoteExplorer() {
|
||||||
)}
|
)}
|
||||||
{!isInstalled && (
|
{!isInstalled && (
|
||||||
<Alert
|
<Alert
|
||||||
title="The Kiwix application is not installed. Please install it to view downloaded ZIM files"
|
title="The Kiwix application is not installed. Please install it to view downloaded content files."
|
||||||
type="warning"
|
type="warning"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
className="!mt-6"
|
className="!mt-6"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<StyledSectionHeader title="Curated ZIM Collections" className="mt-8 !mb-4" />
|
<StyledSectionHeader title="Curated Content Collections" className="mt-8 !mb-4" />
|
||||||
<StyledButton
|
<StyledButton
|
||||||
onClick={() => fetchLatestCollections.mutate()}
|
onClick={() => fetchLatestCollections.mutate()}
|
||||||
disabled={fetchLatestCollections.isPending}
|
disabled={fetchLatestCollections.isPending}
|
||||||
|
|
@ -234,19 +302,46 @@ export default function ZimRemoteExplorer() {
|
||||||
>
|
>
|
||||||
Fetch Latest Collections
|
Fetch Latest Collections
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
<div className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
||||||
{curatedCollections?.map((collection) => (
|
{/* Tiered Category Collections - matches Easy Setup Wizard */}
|
||||||
<CuratedCollectionCard
|
{categories && categories.length > 0 ? (
|
||||||
key={collection.slug}
|
<>
|
||||||
collection={collection}
|
<div className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
onClick={(collection) => confirmDownload(collection)}
|
{categories.map((category) => (
|
||||||
size="large"
|
<CategoryCard
|
||||||
|
key={category.slug}
|
||||||
|
category={category}
|
||||||
|
selectedTier={null}
|
||||||
|
onClick={handleCategoryClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tier Selection Modal */}
|
||||||
|
<TierSelectionModal
|
||||||
|
isOpen={tierModalOpen}
|
||||||
|
onClose={closeTierModal}
|
||||||
|
category={activeCategory}
|
||||||
|
selectedTierSlug={null}
|
||||||
|
onSelectTier={handleTierSelect}
|
||||||
/>
|
/>
|
||||||
))}
|
</>
|
||||||
{curatedCollections && curatedCollections.length === 0 && (
|
) : (
|
||||||
<p className="text-gray-500">No curated collections available.</p>
|
/* Legacy flat collections - fallback if no categories available */
|
||||||
)}
|
<div className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
</div>
|
{curatedCollections?.map((collection) => (
|
||||||
|
<CuratedCollectionCard
|
||||||
|
key={collection.slug}
|
||||||
|
collection={collection}
|
||||||
|
onClick={(collection) => confirmDownload(collection)}
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{curatedCollections && curatedCollections.length === 0 && (
|
||||||
|
<p className="text-gray-500">No curated collections available.</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<StyledSectionHeader title="Browse the Kiwix Library" className="mt-12 mb-4" />
|
<StyledSectionHeader title="Browse the Kiwix Library" className="mt-12 mb-4" />
|
||||||
<div className="flex justify-start mt-4">
|
<div className="flex justify-start mt-4">
|
||||||
<Input
|
<Input
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user