mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-28 03:29:25 +01:00
fix(UI): switch to tabler icons only for consistency
This commit is contained in:
parent
243f749090
commit
0da050c5a3
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Icons from '@heroicons/react/24/solid'
|
import * as Icons from '@tabler/icons-react'
|
||||||
import classNames from '~/lib/classNames'
|
import classNames from '~/lib/classNames'
|
||||||
|
import DynamicIcon from './DynamicIcon'
|
||||||
|
|
||||||
export type AlertProps = React.HTMLAttributes<HTMLDivElement> & {
|
export type AlertProps = React.HTMLAttributes<HTMLDivElement> & {
|
||||||
title: string
|
title: string
|
||||||
|
|
@ -26,26 +27,18 @@ export default function Alert({
|
||||||
const getDefaultIcon = (): keyof typeof Icons => {
|
const getDefaultIcon = (): keyof typeof Icons => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'warning':
|
case 'warning':
|
||||||
return 'ExclamationTriangleIcon'
|
return 'IconAlertTriangle'
|
||||||
case 'error':
|
case 'error':
|
||||||
return 'XCircleIcon'
|
return 'IconXboxX'
|
||||||
case 'success':
|
case 'success':
|
||||||
return 'CheckCircleIcon'
|
return 'IconCircleCheck'
|
||||||
case 'info':
|
case 'info':
|
||||||
return 'InformationCircleIcon'
|
return 'IconInfoCircle'
|
||||||
default:
|
default:
|
||||||
return 'InformationCircleIcon'
|
return 'IconInfoCircle'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const IconComponent = () => {
|
|
||||||
const iconName = icon || getDefaultIcon()
|
|
||||||
const Icon = Icons[iconName]
|
|
||||||
if (!Icon) return null
|
|
||||||
|
|
||||||
return <Icon aria-hidden="true" className={classNames('size-5 shrink-0', getIconColor())} />
|
|
||||||
}
|
|
||||||
|
|
||||||
const getIconColor = () => {
|
const getIconColor = () => {
|
||||||
if (variant === 'solid') return 'text-desert-white'
|
if (variant === 'solid') return 'text-desert-white'
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -165,7 +158,7 @@ export default function Alert({
|
||||||
return (
|
return (
|
||||||
<div {...props} className={classNames(getVariantStyles(), 'p-4', props.className)} role="alert">
|
<div {...props} className={classNames(getVariantStyles(), 'p-4', props.className)} role="alert">
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<IconComponent />
|
<DynamicIcon icon={getDefaultIcon()} className={getIconColor() + ' size-5 shrink-0'} />
|
||||||
|
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h3 className={classNames('text-sm font-semibold', getTitleColor())}>{title}</h3>
|
<h3 className={classNames('text-sm font-semibold', getTitleColor())}>{title}</h3>
|
||||||
|
|
@ -192,7 +185,7 @@ export default function Alert({
|
||||||
)}
|
)}
|
||||||
aria-label="Dismiss alert"
|
aria-label="Dismiss alert"
|
||||||
>
|
>
|
||||||
<Icons.XMarkIcon className="size-5" />
|
<DynamicIcon icon="IconX" className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { IconRefresh } from '@tabler/icons-react'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { ArrowPathIcon } from '@heroicons/react/24/outline'
|
|
||||||
import {
|
import {
|
||||||
ADJECTIVES,
|
ADJECTIVES,
|
||||||
NOUNS,
|
NOUNS,
|
||||||
|
|
@ -118,7 +118,7 @@ export default function BuilderTagSelector({
|
||||||
className="p-2 text-desert-stone-dark hover:text-desert-green hover:bg-desert-stone-lighter rounded-lg transition-colors disabled:opacity-50"
|
className="p-2 text-desert-stone-dark hover:text-desert-green hover:bg-desert-stone-lighter rounded-lg transition-colors disabled:opacity-50"
|
||||||
title="Randomize"
|
title="Randomize"
|
||||||
>
|
>
|
||||||
<ArrowPathIcon className="w-5 h-5" />
|
<IconRefresh className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ const DownloadURLModal: React.FC<DownloadURLModalProps> = ({
|
||||||
onConfirm={() => runPreflightCheck(url)}
|
onConfirm={() => runPreflightCheck(url)}
|
||||||
open={true}
|
open={true}
|
||||||
confirmText="Download"
|
confirmText="Download"
|
||||||
confirmIcon="ArrowDownTrayIcon"
|
confirmIcon="IconDownload"
|
||||||
cancelText="Cancel"
|
cancelText="Cancel"
|
||||||
confirmVariant="primary"
|
confirmVariant="primary"
|
||||||
confirmLoading={loading}
|
confirmLoading={loading}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { InformationCircleIcon } from '@heroicons/react/24/outline'
|
import { IconInfoCircle } from '@tabler/icons-react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
interface InfoTooltipProps {
|
interface InfoTooltipProps {
|
||||||
|
|
@ -20,7 +20,7 @@ export default function InfoTooltip({ text, className = '' }: InfoTooltipProps)
|
||||||
onBlur={() => setIsVisible(false)}
|
onBlur={() => setIsVisible(false)}
|
||||||
aria-label="More information"
|
aria-label="More information"
|
||||||
>
|
>
|
||||||
<InformationCircleIcon className="w-4 h-4" />
|
<IconInfoCircle className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
{isVisible && (
|
{isVisible && (
|
||||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50">
|
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50">
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { CheckCircleIcon } from '@heroicons/react/24/outline'
|
import { IconCircleCheck } from '@tabler/icons-react'
|
||||||
import classNames from '~/lib/classNames'
|
import classNames from '~/lib/classNames'
|
||||||
|
|
||||||
export type InstallActivityFeedProps = {
|
export type InstallActivityFeedProps = {
|
||||||
|
|
@ -41,7 +41,7 @@ const InstallActivityFeed: React.FC<InstallActivityFeedProps> = ({ activity, cla
|
||||||
<>
|
<>
|
||||||
<div className="relative flex size-6 flex-none items-center justify-center bg-transparent">
|
<div className="relative flex size-6 flex-none items-center justify-center bg-transparent">
|
||||||
{activityItem.type === 'completed' ? (
|
{activityItem.type === 'completed' ? (
|
||||||
<CheckCircleIcon aria-hidden="true" className="size-6 text-indigo-600" />
|
<IconCircleCheck aria-hidden="true" className="size-6 text-indigo-600" />
|
||||||
) : (
|
) : (
|
||||||
<div className="size-1.5 rounded-full bg-gray-100 ring-1 ring-gray-300" />
|
<div className="size-1.5 rounded-full bg-gray-100 ring-1 ring-gray-300" />
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import * as Icons from '@heroicons/react/24/outline'
|
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
import DynamicIcon, { DynamicIconName} from './DynamicIcon'
|
||||||
|
import { IconRefresh } from '@tabler/icons-react'
|
||||||
|
|
||||||
export interface StyledButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
export interface StyledButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
// icon should be one of the HeroIcon names, e.g. ArrowTopRightOnSquareIcon
|
icon?: DynamicIconName
|
||||||
icon?: keyof typeof Icons
|
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
variant?: 'primary' | 'secondary' | 'danger' | 'action' | 'success' | 'ghost' | 'outline'
|
variant?: 'primary' | 'secondary' | 'danger' | 'action' | 'success' | 'ghost' | 'outline'
|
||||||
size?: 'sm' | 'md' | 'lg'
|
size?: 'sm' | 'md' | 'lg'
|
||||||
|
|
@ -26,12 +26,6 @@ const StyledButton: React.FC<StyledButtonProps> = ({
|
||||||
return props.disabled || loading
|
return props.disabled || loading
|
||||||
}, [props.disabled, loading])
|
}, [props.disabled, loading])
|
||||||
|
|
||||||
const IconComponent = () => {
|
|
||||||
if (!icon) return null
|
|
||||||
const Icon = Icons[icon]
|
|
||||||
return Icon ? <Icon className={getIconSize()} /> : null
|
|
||||||
}
|
|
||||||
|
|
||||||
const getIconSize = () => {
|
const getIconSize = () => {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 'sm':
|
case 'sm':
|
||||||
|
|
@ -136,7 +130,7 @@ const StyledButton: React.FC<StyledButtonProps> = ({
|
||||||
const getLoadingSpinner = () => {
|
const getLoadingSpinner = () => {
|
||||||
const spinnerSize = size === 'sm' ? 'h-3.5 w-3.5' : size === 'lg' ? 'h-5 w-5' : 'h-4 w-4'
|
const spinnerSize = size === 'sm' ? 'h-3.5 w-3.5' : size === 'lg' ? 'h-5 w-5' : 'h-4 w-4'
|
||||||
return (
|
return (
|
||||||
<Icons.ArrowPathIcon
|
<IconRefresh
|
||||||
className={clsx(spinnerSize, 'animate-spin')}
|
className={clsx(spinnerSize, 'animate-spin')}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
@ -168,7 +162,7 @@ const StyledButton: React.FC<StyledButtonProps> = ({
|
||||||
getLoadingSpinner()
|
getLoadingSpinner()
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{icon && <IconComponent />}
|
{icon && <DynamicIcon icon={icon} className={getIconSize()} />}
|
||||||
{children}
|
{children}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { Dialog, DialogBackdrop, DialogPanel, TransitionChild } from '@headlessui/react'
|
import { Dialog, DialogBackdrop, DialogPanel, TransitionChild } from '@headlessui/react'
|
||||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
|
|
||||||
import classNames from '~/lib/classNames'
|
import classNames from '~/lib/classNames'
|
||||||
import { IconArrowLeft } from '@tabler/icons-react'
|
import { IconArrowLeft } from '@tabler/icons-react'
|
||||||
import { usePage } from '@inertiajs/react'
|
import { usePage } from '@inertiajs/react'
|
||||||
import { UsePageProps } from '../../types/system'
|
import { UsePageProps } from '../../types/system'
|
||||||
|
import { IconMenu2, IconX } from '@tabler/icons-react'
|
||||||
|
|
||||||
type SidebarItem = {
|
type SidebarItem = {
|
||||||
name: string
|
name: string
|
||||||
|
|
@ -89,7 +89,7 @@ const StyledSidebar: React.FC<StyledSidebarProps> = ({ title, items }) => {
|
||||||
className="absolute left-4 top-4 z-50 xl:hidden"
|
className="absolute left-4 top-4 z-50 xl:hidden"
|
||||||
onClick={() => setSidebarOpen(true)}
|
onClick={() => setSidebarOpen(true)}
|
||||||
>
|
>
|
||||||
<Bars3Icon aria-hidden="true" className="size-8" />
|
<IconMenu2 aria-hidden="true" className="size-8" />
|
||||||
</button>
|
</button>
|
||||||
{/* Mobile sidebar */}
|
{/* Mobile sidebar */}
|
||||||
<Dialog open={sidebarOpen} onClose={setSidebarOpen} className="relative z-50 xl:hidden">
|
<Dialog open={sidebarOpen} onClose={setSidebarOpen} className="relative z-50 xl:hidden">
|
||||||
|
|
@ -111,7 +111,7 @@ const StyledSidebar: React.FC<StyledSidebarProps> = ({ title, items }) => {
|
||||||
className="-m-2.5 p-2.5"
|
className="-m-2.5 p-2.5"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Close sidebar</span>
|
<span className="sr-only">Close sidebar</span>
|
||||||
<XMarkIcon aria-hidden="true" className="size-6 text-white" />
|
<IconX aria-hidden="true" className="size-6 text-white" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</TransitionChild>
|
</TransitionChild>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChatBubbleLeftRightIcon } from '@heroicons/react/24/outline'
|
import { IconMessages } from '@tabler/icons-react'
|
||||||
|
|
||||||
interface ChatButtonProps {
|
interface ChatButtonProps {
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
|
|
@ -11,7 +11,7 @@ export default function ChatButton({ onClick }: ChatButtonProps) {
|
||||||
className="fixed bottom-6 right-6 z-40 p-4 bg-desert-green text-white rounded-full shadow-lg hover:bg-desert-green/90 transition-all duration-200 hover:scale-110 focus:outline-none focus:ring-2 focus:ring-desert-green focus:ring-offset-2 cursor-pointer"
|
className="fixed bottom-6 right-6 z-40 p-4 bg-desert-green text-white rounded-full shadow-lg hover:bg-desert-green/90 transition-all duration-200 hover:scale-110 focus:outline-none focus:ring-2 focus:ring-desert-green focus:ring-offset-2 cursor-pointer"
|
||||||
aria-label="Open chat"
|
aria-label="Open chat"
|
||||||
>
|
>
|
||||||
<ChatBubbleLeftRightIcon className="h-6 w-6" />
|
<IconMessages className="h-6 w-6" />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { PaperAirplaneIcon } from '@heroicons/react/24/outline'
|
import { IconSend, IconWand } from '@tabler/icons-react'
|
||||||
import { IconWand } from '@tabler/icons-react'
|
|
||||||
import { useState, useRef, useEffect } from 'react'
|
import { useState, useRef, useEffect } from 'react'
|
||||||
import classNames from '~/lib/classNames'
|
import classNames from '~/lib/classNames'
|
||||||
import { ChatMessage } from '../../../types/chat'
|
import { ChatMessage } from '../../../types/chat'
|
||||||
|
|
@ -139,7 +138,7 @@ export default function ChatInterface({
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="h-6 w-6 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
<div className="h-6 w-6 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<PaperAirplaneIcon className="h-6 w-6" />
|
<IconSend className="h-6 w-6" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { ChatBubbleLeftIcon } from '@heroicons/react/24/outline'
|
|
||||||
import classNames from '~/lib/classNames'
|
import classNames from '~/lib/classNames'
|
||||||
import StyledButton from '../StyledButton'
|
import StyledButton from '../StyledButton'
|
||||||
import { router } from '@inertiajs/react'
|
import { router } from '@inertiajs/react'
|
||||||
import { ChatSession } from '../../../types/chat'
|
import { ChatSession } from '../../../types/chat'
|
||||||
|
import { IconMessage } from '@tabler/icons-react'
|
||||||
|
|
||||||
interface ChatSidebarProps {
|
interface ChatSidebarProps {
|
||||||
sessions: ChatSession[]
|
sessions: ChatSession[]
|
||||||
|
|
@ -24,7 +24,7 @@ export default function ChatSidebar({
|
||||||
return (
|
return (
|
||||||
<div className="w-64 bg-gray-50 border-r border-gray-200 flex flex-col h-full">
|
<div className="w-64 bg-gray-50 border-r border-gray-200 flex flex-col h-full">
|
||||||
<div className="p-4 border-b border-gray-200 h-[75px] flex items-center justify-center">
|
<div className="p-4 border-b border-gray-200 h-[75px] flex items-center justify-center">
|
||||||
<StyledButton onClick={onNewChat} icon="PlusIcon" variant="primary" fullWidth>
|
<StyledButton onClick={onNewChat} icon="IconPlus" variant="primary" fullWidth>
|
||||||
New Chat
|
New Chat
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -46,7 +46,7 @@ export default function ChatSidebar({
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<ChatBubbleLeftIcon
|
<IconMessage
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'h-5 w-5 mt-0.5 flex-shrink-0',
|
'h-5 w-5 mt-0.5 flex-shrink-0',
|
||||||
activeSessionId === session.id ? 'text-white' : 'text-gray-400'
|
activeSessionId === session.id ? 'text-white' : 'text-gray-400'
|
||||||
|
|
@ -83,7 +83,7 @@ export default function ChatSidebar({
|
||||||
router.visit('/home')
|
router.visit('/home')
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
icon={isInModal ? 'ArrowTopRightOnSquareIcon' : 'HomeIcon'}
|
icon={isInModal ? 'IconExternalLink' : 'IconHome'}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
@ -94,7 +94,7 @@ export default function ChatSidebar({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.visit('/settings/models')
|
router.visit('/settings/models')
|
||||||
}}
|
}}
|
||||||
icon="CircleStackIcon"
|
icon="IconDatabase"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
@ -105,7 +105,7 @@ export default function ChatSidebar({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.visit('/knowledge-base')
|
router.visit('/knowledge-base')
|
||||||
}}
|
}}
|
||||||
icon="AcademicCapIcon"
|
icon="IconBrain"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
@ -114,7 +114,7 @@ export default function ChatSidebar({
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
<StyledButton
|
<StyledButton
|
||||||
onClick={onClearHistory}
|
onClick={onClearHistory}
|
||||||
icon="TrashIcon"
|
icon="IconTrash"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
size="sm"
|
size="sm"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { XMarkIcon } from '@heroicons/react/24/outline'
|
|
||||||
import { useState, useCallback, useEffect } from 'react'
|
import { useState, useCallback, useEffect } from 'react'
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||||
import ChatSidebar from './ChatSidebar'
|
import ChatSidebar from './ChatSidebar'
|
||||||
|
|
@ -9,6 +8,7 @@ import { formatBytes } from '~/lib/util'
|
||||||
import { useModals } from '~/context/ModalContext'
|
import { useModals } from '~/context/ModalContext'
|
||||||
import { ChatMessage } from '../../../types/chat'
|
import { ChatMessage } from '../../../types/chat'
|
||||||
import classNames from '~/lib/classNames'
|
import classNames from '~/lib/classNames'
|
||||||
|
import { IconX } from '@tabler/icons-react'
|
||||||
|
|
||||||
interface ChatProps {
|
interface ChatProps {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
|
|
@ -254,7 +254,7 @@ export default function Chat({ enabled, isInModal, onClose }: ChatProps) {
|
||||||
}}
|
}}
|
||||||
className="rounded-lg hover:bg-gray-100 transition-colors"
|
className="rounded-lg hover:bg-gray-100 transition-colors"
|
||||||
>
|
>
|
||||||
<XMarkIcon className="h-6 w-6 text-gray-500" />
|
<IconX className="h-6 w-6 text-gray-500" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,24 @@
|
||||||
import {
|
|
||||||
ChartBarIcon,
|
|
||||||
Cog6ToothIcon,
|
|
||||||
CommandLineIcon,
|
|
||||||
FolderIcon,
|
|
||||||
MagnifyingGlassIcon,
|
|
||||||
} from '@heroicons/react/24/outline'
|
|
||||||
import {
|
import {
|
||||||
IconArrowBigUpLines,
|
IconArrowBigUpLines,
|
||||||
|
IconChartBar,
|
||||||
IconDashboard,
|
IconDashboard,
|
||||||
IconDatabaseStar,
|
IconDatabaseStar,
|
||||||
|
IconFolder,
|
||||||
IconGavel,
|
IconGavel,
|
||||||
IconMapRoute,
|
IconMapRoute,
|
||||||
|
IconSettings,
|
||||||
|
IconTerminal2,
|
||||||
|
IconZoom
|
||||||
} from '@tabler/icons-react'
|
} from '@tabler/icons-react'
|
||||||
import StyledSidebar from '~/components/StyledSidebar'
|
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: '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: IconTerminal2, current: false },
|
||||||
{ name: 'Benchmark', href: '/settings/benchmark', icon: ChartBarIcon, current: false },
|
{ name: 'Benchmark', href: '/settings/benchmark', icon: IconChartBar, current: false },
|
||||||
{ name: 'Content Explorer', href: '/settings/zim/remote-explorer', icon: MagnifyingGlassIcon, current: false },
|
{ name: 'Content Explorer', href: '/settings/zim/remote-explorer', icon: IconZoom, current: false },
|
||||||
{ name: 'Content Manager', href: '/settings/zim', icon: FolderIcon, current: false },
|
{ name: 'Content Manager', href: '/settings/zim', icon: IconFolder, current: false },
|
||||||
{ name: 'Maps Manager', href: '/settings/maps', icon: IconMapRoute, current: false },
|
{ name: 'Maps Manager', href: '/settings/maps', icon: IconMapRoute, current: false },
|
||||||
{
|
{
|
||||||
name: 'Service Logs & Metrics',
|
name: 'Service Logs & Metrics',
|
||||||
|
|
@ -35,7 +33,7 @@ const navigation = [
|
||||||
icon: IconArrowBigUpLines,
|
icon: IconArrowBigUpLines,
|
||||||
current: false,
|
current: false,
|
||||||
},
|
},
|
||||||
{ name: 'System', href: '/settings/system', icon: Cog6ToothIcon, current: false },
|
{ name: 'System', href: '/settings/system', icon: IconSettings, current: false },
|
||||||
{ name: 'Legal Notices', href: '/settings/legal', icon: IconGavel, current: false },
|
{ name: 'Legal Notices', href: '/settings/legal', icon: IconGavel, current: false },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export default function EasySetupWizardComplete() {
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-center mt-8 pt-4 border-t border-desert-stone-light">
|
<div className="flex justify-center mt-8 pt-4 border-t border-desert-stone-light">
|
||||||
<div className="flex space-x-4">
|
<div className="flex space-x-4">
|
||||||
<StyledButton onClick={() => router.visit('/home')} icon="HomeIcon">
|
<StyledButton onClick={() => router.visit('/home')} icon="IconHome">
|
||||||
Go to Home
|
Go to Home
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1210,7 +1210,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
onClick={handleBack}
|
onClick={handleBack}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
icon="ChevronLeftIcon"
|
icon="IconChevronLeft"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -1244,7 +1244,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
onClick={handleNext}
|
onClick={handleNext}
|
||||||
disabled={!canProceedToNextStep() || isProcessing}
|
disabled={!canProceedToNextStep() || isProcessing}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
icon="ChevronRightIcon"
|
icon="IconChevronRight"
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -1254,7 +1254,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
disabled={isProcessing || !isOnline || !anySelectionMade}
|
disabled={isProcessing || !isOnline || !anySelectionMade}
|
||||||
loading={isProcessing}
|
loading={isProcessing}
|
||||||
variant="success"
|
variant="success"
|
||||||
icon="CheckIcon"
|
icon="IconCheck"
|
||||||
>
|
>
|
||||||
Complete Setup
|
Complete Setup
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ export default function KnowledgeBase() {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="lg"
|
size="lg"
|
||||||
icon="ArrowUpCircleIcon"
|
icon="IconUpload"
|
||||||
onClick={handleUpload}
|
onClick={handleUpload}
|
||||||
disabled={files.length === 0 || uploadMutation.isPending}
|
disabled={files.length === 0 || uploadMutation.isPending}
|
||||||
loading={uploadMutation.isPending}
|
loading={uploadMutation.isPending}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export default function Maps(props: {
|
||||||
<p className="text-lg text-gray-600">Back to Home</p>
|
<p className="text-lg text-gray-600">Back to Home</p>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/settings/maps">
|
<Link href="/settings/maps">
|
||||||
<StyledButton variant="primary" icon="Cog6ToothIcon">
|
<StyledButton variant="primary" icon="IconSettings">
|
||||||
Manage Map Regions
|
Manage Map Regions
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -39,7 +39,7 @@ export default function Maps(props: {
|
||||||
buttonProps={{
|
buttonProps={{
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
children: 'Go to Map Settings',
|
children: 'Go to Map Settings',
|
||||||
icon: 'Cog6ToothIcon',
|
icon: 'IconSettings',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
window.location.href = '/settings/maps'
|
window.location.href = '/settings/maps'
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ import LoadingSpinner from '~/components/LoadingSpinner'
|
||||||
import useErrorNotification from '~/hooks/useErrorNotification'
|
import useErrorNotification from '~/hooks/useErrorNotification'
|
||||||
import useInternetStatus from '~/hooks/useInternetStatus'
|
import useInternetStatus from '~/hooks/useInternetStatus'
|
||||||
import useServiceInstallationActivity from '~/hooks/useServiceInstallationActivity'
|
import useServiceInstallationActivity from '~/hooks/useServiceInstallationActivity'
|
||||||
import { ArrowDownTrayIcon } from '@heroicons/react/24/outline'
|
import { IconCheck, IconDownload } from '@tabler/icons-react'
|
||||||
import { IconCheck } from '@tabler/icons-react'
|
|
||||||
|
|
||||||
export default function SettingsPage(props: { system: { services: ServiceSlim[] } }) {
|
export default function SettingsPage(props: { system: { services: ServiceSlim[] } }) {
|
||||||
const { openModal, closeAllModals } = useModals()
|
const { openModal, closeAllModals } = useModals()
|
||||||
|
|
@ -48,7 +47,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
||||||
confirmText="Install"
|
confirmText="Install"
|
||||||
cancelText="Cancel"
|
cancelText="Cancel"
|
||||||
confirmVariant="primary"
|
confirmVariant="primary"
|
||||||
icon={<ArrowDownTrayIcon className="h-12 w-12 text-desert-green" />}
|
icon={<IconDownload className="h-12 w-12 text-desert-green" />}
|
||||||
>
|
>
|
||||||
<p className="text-gray-700">
|
<p className="text-gray-700">
|
||||||
Are you sure you want to install {service.friendly_name || service.service_name}? This
|
Are you sure you want to install {service.friendly_name || service.service_name}? This
|
||||||
|
|
@ -132,7 +131,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
||||||
const AppActions = ({ record }: { record: ServiceSlim }) => {
|
const AppActions = ({ record }: { record: ServiceSlim }) => {
|
||||||
const ForceReinstallButton = () => (
|
const ForceReinstallButton = () => (
|
||||||
<StyledButton
|
<StyledButton
|
||||||
icon="ExclamationTriangleIcon"
|
icon="IconDownload"
|
||||||
variant="action"
|
variant="action"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openModal(
|
openModal(
|
||||||
|
|
@ -165,7 +164,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
||||||
return (
|
return (
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<StyledButton
|
<StyledButton
|
||||||
icon={'ArrowDownTrayIcon'}
|
icon={'IconDownload'}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={() => handleInstallService(record)}
|
onClick={() => handleInstallService(record)}
|
||||||
disabled={isInstalling || !isOnline}
|
disabled={isInstalling || !isOnline}
|
||||||
|
|
@ -181,7 +180,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
||||||
return (
|
return (
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<StyledButton
|
<StyledButton
|
||||||
icon={'ArrowTopRightOnSquareIcon'}
|
icon={'IconExternalLink'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
window.open(getServiceLink(record.ui_location || 'unknown'), '_blank')
|
window.open(getServiceLink(record.ui_location || 'unknown'), '_blank')
|
||||||
}}
|
}}
|
||||||
|
|
@ -191,7 +190,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
||||||
{record.status && record.status !== 'unknown' && (
|
{record.status && record.status !== 'unknown' && (
|
||||||
<>
|
<>
|
||||||
<StyledButton
|
<StyledButton
|
||||||
icon={record.status === 'running' ? 'StopIcon' : 'PlayIcon'}
|
icon={record.status === 'running' ? 'IconPlayerStop' : 'IconPlayerPlay'}
|
||||||
variant={record.status === 'running' ? 'action' : undefined}
|
variant={record.status === 'running' ? 'action' : undefined}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openModal(
|
openModal(
|
||||||
|
|
@ -219,7 +218,7 @@ export default function SettingsPage(props: { system: { services: ServiceSlim[]
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
{record.status === 'running' && (
|
{record.status === 'running' && (
|
||||||
<StyledButton
|
<StyledButton
|
||||||
icon="ArrowPathIcon"
|
icon="IconRefresh"
|
||||||
variant="action"
|
variant="action"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openModal(
|
openModal(
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,7 @@ import Alert from '~/components/Alert'
|
||||||
import StyledButton from '~/components/StyledButton'
|
import StyledButton from '~/components/StyledButton'
|
||||||
import InfoTooltip from '~/components/InfoTooltip'
|
import InfoTooltip from '~/components/InfoTooltip'
|
||||||
import BuilderTagSelector from '~/components/BuilderTagSelector'
|
import BuilderTagSelector from '~/components/BuilderTagSelector'
|
||||||
import {
|
import { IconRobot, IconChartBar, IconCpu, IconDatabase, IconServer, IconChevronDown, IconClock } from '@tabler/icons-react'
|
||||||
ChartBarIcon,
|
|
||||||
CpuChipIcon,
|
|
||||||
CircleStackIcon,
|
|
||||||
ServerIcon,
|
|
||||||
ChevronDownIcon,
|
|
||||||
ClockIcon,
|
|
||||||
} from '@heroicons/react/24/outline'
|
|
||||||
import { IconRobot } from '@tabler/icons-react'
|
|
||||||
import { useTransmit } from 'react-adonis-transmit'
|
import { useTransmit } from 'react-adonis-transmit'
|
||||||
import { BenchmarkProgress, BenchmarkStatus } from '../../../types/benchmark'
|
import { BenchmarkProgress, BenchmarkStatus } from '../../../types/benchmark'
|
||||||
import BenchmarkResult from '#models/benchmark_result'
|
import BenchmarkResult from '#models/benchmark_result'
|
||||||
|
|
@ -378,7 +370,7 @@ export default function BenchmarkPage(props: {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
onClick={handleFullBenchmarkClick}
|
onClick={handleFullBenchmarkClick}
|
||||||
disabled={runBenchmark.isPending}
|
disabled={runBenchmark.isPending}
|
||||||
icon='PlayIcon'
|
icon='IconPlayerPlay'
|
||||||
>
|
>
|
||||||
Run Full Benchmark
|
Run Full Benchmark
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -386,7 +378,7 @@ export default function BenchmarkPage(props: {
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => runBenchmark.mutate('system')}
|
onClick={() => runBenchmark.mutate('system')}
|
||||||
disabled={runBenchmark.isPending}
|
disabled={runBenchmark.isPending}
|
||||||
icon='CpuChipIcon'
|
icon='IconCpu'
|
||||||
>
|
>
|
||||||
System Only
|
System Only
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -394,7 +386,7 @@ export default function BenchmarkPage(props: {
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => runBenchmark.mutate('ai')}
|
onClick={() => runBenchmark.mutate('ai')}
|
||||||
disabled={runBenchmark.isPending || !aiInstalled}
|
disabled={runBenchmark.isPending || !aiInstalled}
|
||||||
icon='SparklesIcon'
|
icon='IconWand'
|
||||||
title={!aiInstalled ? 'AI Assistant must be installed to run AI benchmark' : undefined}
|
title={!aiInstalled ? 'AI Assistant must be installed to run AI benchmark' : undefined}
|
||||||
>
|
>
|
||||||
AI Only
|
AI Only
|
||||||
|
|
@ -431,7 +423,7 @@ export default function BenchmarkPage(props: {
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="cpu"
|
variant="cpu"
|
||||||
subtext="out of 100"
|
subtext="out of 100"
|
||||||
icon={<ChartBarIcon className="w-8 h-8" />}
|
icon={<IconChartBar className="w-8 h-8" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 space-y-4">
|
<div className="flex-1 space-y-4">
|
||||||
|
|
@ -482,7 +474,7 @@ export default function BenchmarkPage(props: {
|
||||||
anonymous: shareAnonymously
|
anonymous: shareAnonymously
|
||||||
})}
|
})}
|
||||||
disabled={submitResult.isPending}
|
disabled={submitResult.isPending}
|
||||||
icon='CloudArrowUpIcon'
|
icon='IconCloudUpload'
|
||||||
>
|
>
|
||||||
{submitResult.isPending ? 'Submitting...' : 'Share with Community'}
|
{submitResult.isPending ? 'Submitting...' : 'Share with Community'}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -544,7 +536,7 @@ export default function BenchmarkPage(props: {
|
||||||
label="CPU"
|
label="CPU"
|
||||||
size="md"
|
size="md"
|
||||||
variant="cpu"
|
variant="cpu"
|
||||||
icon={<CpuChipIcon className="w-6 h-6" />}
|
icon={<IconCpu className="w-6 h-6" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
||||||
|
|
@ -553,7 +545,7 @@ export default function BenchmarkPage(props: {
|
||||||
label="Memory"
|
label="Memory"
|
||||||
size="md"
|
size="md"
|
||||||
variant="memory"
|
variant="memory"
|
||||||
icon={<CircleStackIcon className="w-6 h-6" />}
|
icon={<IconDatabase className="w-6 h-6" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
||||||
|
|
@ -562,7 +554,7 @@ export default function BenchmarkPage(props: {
|
||||||
label="Disk Read"
|
label="Disk Read"
|
||||||
size="md"
|
size="md"
|
||||||
variant="disk"
|
variant="disk"
|
||||||
icon={<ServerIcon className="w-6 h-6" />}
|
icon={<IconServer className="w-6 h-6" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm">
|
||||||
|
|
@ -571,7 +563,7 @@ export default function BenchmarkPage(props: {
|
||||||
label="Disk Write"
|
label="Disk Write"
|
||||||
size="md"
|
size="md"
|
||||||
variant="disk"
|
variant="disk"
|
||||||
icon={<ServerIcon className="w-6 h-6" />}
|
icon={<IconServer className="w-6 h-6" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -646,7 +638,7 @@ export default function BenchmarkPage(props: {
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<InfoCard
|
<InfoCard
|
||||||
title="Processor"
|
title="Processor"
|
||||||
icon={<CpuChipIcon className="w-6 h-6" />}
|
icon={<IconCpu className="w-6 h-6" />}
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
data={[
|
data={[
|
||||||
{ label: 'Model', value: latestResult.cpu_model },
|
{ label: 'Model', value: latestResult.cpu_model },
|
||||||
|
|
@ -656,7 +648,7 @@ export default function BenchmarkPage(props: {
|
||||||
/>
|
/>
|
||||||
<InfoCard
|
<InfoCard
|
||||||
title="System"
|
title="System"
|
||||||
icon={<ServerIcon className="w-6 h-6" />}
|
icon={<IconServer className="w-6 h-6" />}
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
data={[
|
data={[
|
||||||
{ label: 'RAM', value: formatBytes(latestResult.ram_bytes) },
|
{ label: 'RAM', value: formatBytes(latestResult.ram_bytes) },
|
||||||
|
|
@ -697,7 +689,7 @@ export default function BenchmarkPage(props: {
|
||||||
<div className="font-bold text-desert-green">{latestResult.nomad_score.toFixed(1)}</div>
|
<div className="font-bold text-desert-green">{latestResult.nomad_score.toFixed(1)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ChevronDownIcon
|
<IconChevronDown
|
||||||
className={`w-5 h-5 text-desert-stone-dark transition-transform ${showDetails ? 'rotate-180' : ''}`}
|
className={`w-5 h-5 text-desert-stone-dark transition-transform ${showDetails ? 'rotate-180' : ''}`}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -799,12 +791,12 @@ export default function BenchmarkPage(props: {
|
||||||
className="w-full p-4 flex items-center justify-between hover:bg-desert-stone-lighter/30 transition-colors"
|
className="w-full p-4 flex items-center justify-between hover:bg-desert-stone-lighter/30 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ClockIcon className="w-5 h-5 text-desert-stone-dark" />
|
<IconClock className="w-5 h-5 text-desert-stone-dark" />
|
||||||
<span className="font-medium text-desert-green">
|
<span className="font-medium text-desert-green">
|
||||||
{benchmarkHistory.length} benchmark{benchmarkHistory.length !== 1 ? 's' : ''} recorded
|
{benchmarkHistory.length} benchmark{benchmarkHistory.length !== 1 ? 's' : ''} recorded
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<ChevronDownIcon
|
<IconChevronDown
|
||||||
className={`w-5 h-5 text-desert-stone-dark transition-transform ${showHistory ? 'rotate-180' : ''}`}
|
className={`w-5 h-5 text-desert-stone-dark transition-transform ${showHistory ? 'rotate-180' : ''}`}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ export default function MapsManager(props: {
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={openDownloadModal}
|
onClick={openDownloadModal}
|
||||||
loading={downloading}
|
loading={downloading}
|
||||||
icon="CloudArrowDownIcon"
|
icon="IconCloudDownload"
|
||||||
>
|
>
|
||||||
Download Custom Map File
|
Download Custom Map File
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -213,7 +213,7 @@ export default function MapsManager(props: {
|
||||||
buttonProps={{
|
buttonProps={{
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
children: 'Download Base Assets',
|
children: 'Download Base Assets',
|
||||||
icon: 'ArrowDownTrayIcon',
|
icon: 'IconDownload',
|
||||||
loading: downloading,
|
loading: downloading,
|
||||||
onClick: () => downloadBaseAssets(),
|
onClick: () => downloadBaseAssets(),
|
||||||
}}
|
}}
|
||||||
|
|
@ -223,7 +223,7 @@ export default function MapsManager(props: {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
onClick={() => fetchLatestCollections.mutate()}
|
onClick={() => fetchLatestCollections.mutate()}
|
||||||
disabled={fetchLatestCollections.isPending}
|
disabled={fetchLatestCollections.isPending}
|
||||||
icon="CloudArrowDownIcon"
|
icon="IconCloudDownload"
|
||||||
>
|
>
|
||||||
Fetch Latest Collections
|
Fetch Latest Collections
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -254,7 +254,7 @@ export default function MapsManager(props: {
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<StyledButton
|
<StyledButton
|
||||||
variant="danger"
|
variant="danger"
|
||||||
icon={'TrashIcon'}
|
icon={'IconTrash'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
confirmDeleteFile(record)
|
confirmDeleteFile(record)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,10 @@ import { formatBytes } from '~/lib/util'
|
||||||
import CircularGauge from '~/components/systeminfo/CircularGauge'
|
import CircularGauge from '~/components/systeminfo/CircularGauge'
|
||||||
import HorizontalBarChart from '~/components/HorizontalBarChart'
|
import HorizontalBarChart from '~/components/HorizontalBarChart'
|
||||||
import InfoCard from '~/components/systeminfo/InfoCard'
|
import InfoCard from '~/components/systeminfo/InfoCard'
|
||||||
import {
|
|
||||||
CpuChipIcon,
|
|
||||||
CircleStackIcon,
|
|
||||||
ServerIcon,
|
|
||||||
ComputerDesktopIcon,
|
|
||||||
} from '@heroicons/react/24/outline'
|
|
||||||
import Alert from '~/components/Alert'
|
import Alert from '~/components/Alert'
|
||||||
import { useSystemInfo } from '~/hooks/useSystemInfo'
|
import { useSystemInfo } from '~/hooks/useSystemInfo'
|
||||||
import StatusCard from '~/components/systeminfo/StatusCard'
|
import StatusCard from '~/components/systeminfo/StatusCard'
|
||||||
|
import { IconCpu, IconDatabase, IconServer, IconDeviceDesktop } from '@tabler/icons-react'
|
||||||
|
|
||||||
export default function SettingsPage(props: {
|
export default function SettingsPage(props: {
|
||||||
system: { info: SystemInformationResponse | undefined }
|
system: { info: SystemInformationResponse | undefined }
|
||||||
|
|
@ -35,7 +30,13 @@ export default function SettingsPage(props: {
|
||||||
// Build storage display items - fall back to fsSize when disk array is empty
|
// Build storage display items - fall back to fsSize when disk array is empty
|
||||||
// (Same approach as Easy Setup wizard fix from PR #90)
|
// (Same approach as Easy Setup wizard fix from PR #90)
|
||||||
const validDisks = info?.disk?.filter((d) => d.totalSize > 0) || []
|
const validDisks = info?.disk?.filter((d) => d.totalSize > 0) || []
|
||||||
let storageItems: { label: string; value: number; total: string; used: string; subtext: string }[] = []
|
let storageItems: {
|
||||||
|
label: string
|
||||||
|
value: number
|
||||||
|
total: string
|
||||||
|
used: string
|
||||||
|
subtext: string
|
||||||
|
}[] = []
|
||||||
if (validDisks.length > 0) {
|
if (validDisks.length > 0) {
|
||||||
storageItems = validDisks.map((disk) => ({
|
storageItems = validDisks.map((disk) => ({
|
||||||
label: disk.name || 'Unknown',
|
label: disk.name || 'Unknown',
|
||||||
|
|
@ -100,7 +101,7 @@ export default function SettingsPage(props: {
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="cpu"
|
variant="cpu"
|
||||||
subtext={`${info?.cpu.cores || 0} cores`}
|
subtext={`${info?.cpu.cores || 0} cores`}
|
||||||
icon={<CpuChipIcon className="w-8 h-8" />}
|
icon={<IconCpu className="w-8 h-8" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm hover:shadow-lg transition-shadow">
|
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm hover:shadow-lg transition-shadow">
|
||||||
|
|
@ -110,7 +111,7 @@ export default function SettingsPage(props: {
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="memory"
|
variant="memory"
|
||||||
subtext={`${formatBytes(info?.mem.used || 0)} / ${formatBytes(info?.mem.total || 0)}`}
|
subtext={`${formatBytes(info?.mem.used || 0)} / ${formatBytes(info?.mem.total || 0)}`}
|
||||||
icon={<CircleStackIcon className="w-8 h-8" />}
|
icon={<IconDatabase className="w-8 h-8" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm hover:shadow-lg transition-shadow">
|
<div className="bg-desert-white rounded-lg p-6 border border-desert-stone-light shadow-sm hover:shadow-lg transition-shadow">
|
||||||
|
|
@ -120,7 +121,7 @@ export default function SettingsPage(props: {
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="disk"
|
variant="disk"
|
||||||
subtext={`${formatBytes(info?.mem.swapused || 0)} / ${formatBytes(info?.mem.swaptotal || 0)}`}
|
subtext={`${formatBytes(info?.mem.swapused || 0)} / ${formatBytes(info?.mem.swaptotal || 0)}`}
|
||||||
icon={<ServerIcon className="w-8 h-8" />}
|
icon={<IconServer className="w-8 h-8" />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -134,7 +135,7 @@ export default function SettingsPage(props: {
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<InfoCard
|
<InfoCard
|
||||||
title="Operating System"
|
title="Operating System"
|
||||||
icon={<ComputerDesktopIcon className="w-6 h-6" />}
|
icon={<IconDeviceDesktop className="w-6 h-6" />}
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
data={[
|
data={[
|
||||||
{ label: 'Distribution', value: info?.os.distro },
|
{ label: 'Distribution', value: info?.os.distro },
|
||||||
|
|
@ -146,7 +147,7 @@ export default function SettingsPage(props: {
|
||||||
/>
|
/>
|
||||||
<InfoCard
|
<InfoCard
|
||||||
title="Processor"
|
title="Processor"
|
||||||
icon={<CpuChipIcon className="w-6 h-6" />}
|
icon={<IconCpu className="w-6 h-6" />}
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
data={[
|
data={[
|
||||||
{ label: 'Manufacturer', value: info?.cpu.manufacturer },
|
{ label: 'Manufacturer', value: info?.cpu.manufacturer },
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ export default function SystemUpdatePage(props: {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="lg"
|
size="lg"
|
||||||
icon="ArrowDownTrayIcon"
|
icon="IconDownload"
|
||||||
onClick={handleStartUpdate}
|
onClick={handleStartUpdate}
|
||||||
disabled={!props.system.updateAvailable}
|
disabled={!props.system.updateAvailable}
|
||||||
>
|
>
|
||||||
|
|
@ -270,7 +270,7 @@ export default function SystemUpdatePage(props: {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="lg"
|
size="lg"
|
||||||
icon="ArrowPathIcon"
|
icon="IconRefresh"
|
||||||
onClick={() => window.location.reload()}
|
onClick={() => window.location.reload()}
|
||||||
>
|
>
|
||||||
Check Again
|
Check Again
|
||||||
|
|
@ -323,7 +323,7 @@ export default function SystemUpdatePage(props: {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
icon="DocumentTextIcon"
|
icon="IconLogs"
|
||||||
onClick={handleViewLogs}
|
onClick={handleViewLogs}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ export default function ZimPage() {
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<StyledButton
|
<StyledButton
|
||||||
variant="danger"
|
variant="danger"
|
||||||
icon={'TrashIcon'}
|
icon={'IconTrash'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
confirmDeleteFile(record)
|
confirmDeleteFile(record)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ export default function ZimRemoteExplorer() {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
onClick={() => fetchLatestCollections.mutate()}
|
onClick={() => fetchLatestCollections.mutate()}
|
||||||
disabled={fetchLatestCollections.isPending}
|
disabled={fetchLatestCollections.isPending}
|
||||||
icon="CloudArrowDownIcon"
|
icon="IconCloudDownload"
|
||||||
>
|
>
|
||||||
Fetch Latest Collections
|
Fetch Latest Collections
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -404,7 +404,7 @@ export default function ZimRemoteExplorer() {
|
||||||
return (
|
return (
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<StyledButton
|
<StyledButton
|
||||||
icon={'ArrowDownTrayIcon'}
|
icon={'IconDownload'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
confirmDownload(record)
|
confirmDownload(record)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { NotificationContext, Notification } from '../context/NotificationContext'
|
import { NotificationContext, Notification } from '../context/NotificationContext'
|
||||||
import {
|
import { IconExclamationCircle, IconCircleCheck, IconInfoCircle } from '@tabler/icons-react'
|
||||||
CheckCircleIcon,
|
|
||||||
InformationCircleIcon,
|
|
||||||
ExclamationTriangleIcon,
|
|
||||||
} from '@heroicons/react/24/outline'
|
|
||||||
|
|
||||||
const NotificationsProvider = ({ children }: { children: React.ReactNode }) => {
|
const NotificationsProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const [notifications, setNotifications] = useState<(Notification & { id: string })[]>([])
|
const [notifications, setNotifications] = useState<(Notification & { id: string })[]>([])
|
||||||
|
|
@ -32,13 +28,13 @@ const NotificationsProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const Icon = ({ type }: { type: string }) => {
|
const Icon = ({ type }: { type: string }) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'error':
|
case 'error':
|
||||||
return <ExclamationTriangleIcon className="h-5 w-5 text-red-500" />
|
return <IconExclamationCircle className="h-5 w-5 text-red-500" />
|
||||||
case 'success':
|
case 'success':
|
||||||
return <CheckCircleIcon className="h-5 w-5 text-green-500" />
|
return <IconCircleCheck className="h-5 w-5 text-green-500" />
|
||||||
case 'info':
|
case 'info':
|
||||||
return <InformationCircleIcon className="h-5 w-5 text-blue-500" />
|
return <IconInfoCircle className="h-5 w-5 text-blue-500" />
|
||||||
default:
|
default:
|
||||||
return <InformationCircleIcon className="h-5 w-5 text-blue-500" />
|
return <IconInfoCircle className="h-5 w-5 text-blue-500" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
admin/package-lock.json
generated
10
admin/package-lock.json
generated
|
|
@ -21,7 +21,6 @@
|
||||||
"@adonisjs/transmit-client": "^1.0.0",
|
"@adonisjs/transmit-client": "^1.0.0",
|
||||||
"@adonisjs/vite": "^4.0.0",
|
"@adonisjs/vite": "^4.0.0",
|
||||||
"@headlessui/react": "^2.2.4",
|
"@headlessui/react": "^2.2.4",
|
||||||
"@heroicons/react": "^2.2.0",
|
|
||||||
"@inertiajs/react": "^2.0.13",
|
"@inertiajs/react": "^2.0.13",
|
||||||
"@markdoc/markdoc": "^0.5.2",
|
"@markdoc/markdoc": "^0.5.2",
|
||||||
"@protomaps/basemaps": "^5.7.0",
|
"@protomaps/basemaps": "^5.7.0",
|
||||||
|
|
@ -2021,15 +2020,6 @@
|
||||||
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@heroicons/react": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">= 16 || ^19.0.0-rc"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@humanfs/core": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@
|
||||||
"@adonisjs/transmit-client": "^1.0.0",
|
"@adonisjs/transmit-client": "^1.0.0",
|
||||||
"@adonisjs/vite": "^4.0.0",
|
"@adonisjs/vite": "^4.0.0",
|
||||||
"@headlessui/react": "^2.2.4",
|
"@headlessui/react": "^2.2.4",
|
||||||
"@heroicons/react": "^2.2.0",
|
|
||||||
"@inertiajs/react": "^2.0.13",
|
"@inertiajs/react": "^2.0.13",
|
||||||
"@markdoc/markdoc": "^0.5.2",
|
"@markdoc/markdoc": "^0.5.2",
|
||||||
"@protomaps/basemaps": "^5.7.0",
|
"@protomaps/basemaps": "^5.7.0",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user