feat: add loading indicators for instant feedback on list updates

This commit is contained in:
Wikid82
2025-11-22 19:55:55 -05:00
parent 09b51a933b
commit 557f9af19b
6 changed files with 22 additions and 8 deletions
+2 -1
View File
@@ -4,7 +4,7 @@ import * as api from '../api/domains'
export function useDomains() {
const queryClient = useQueryClient()
const { data: domains = [], isLoading, error } = useQuery({
const { data: domains = [], isLoading, isFetching, error } = useQuery({
queryKey: ['domains'],
queryFn: api.getDomains,
})
@@ -26,6 +26,7 @@ export function useDomains() {
return {
domains,
isLoading,
isFetching,
error,
createDomain: createMutation.mutateAsync,
deleteDomain: deleteMutation.mutateAsync,
+1
View File
@@ -42,6 +42,7 @@ export function useProxyHosts() {
return {
hosts: query.data || [],
loading: query.isLoading,
isFetching: query.isFetching,
error: query.error ? (query.error as Error).message : null,
createHost: createMutation.mutateAsync,
updateHost: (uuid: string, data: Partial<ProxyHost>) => updateMutation.mutateAsync({ uuid, data }),
+1
View File
@@ -47,6 +47,7 @@ export function useRemoteServers(enabledOnly = false) {
return {
servers: query.data || [],
loading: query.isLoading,
isFetching: query.isFetching,
error: query.error ? (query.error as Error).message : null,
createServer: createMutation.mutateAsync,
updateServer: (uuid: string, data: Partial<RemoteServer>) => updateMutation.mutateAsync({ uuid, data }),
+6 -3
View File
@@ -1,9 +1,9 @@
import { useState } from 'react'
import { useDomains } from '../hooks/useDomains'
import { Trash2, Plus, Globe } from 'lucide-react'
import { Trash2, Plus, Globe, Loader2 } from 'lucide-react'
export default function Domains() {
const { domains, isLoading, error, createDomain, deleteDomain } = useDomains()
const { domains, isLoading, isFetching, error, createDomain, deleteDomain } = useDomains()
const [newDomain, setNewDomain] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
@@ -38,7 +38,10 @@ export default function Domains() {
return (
<div className="p-8">
<div className="flex items-center justify-between mb-6">
<h1 className="text-3xl font-bold text-white">Domains</h1>
<div className="flex items-center gap-3">
<h1 className="text-3xl font-bold text-white">Domains</h1>
{isFetching && !isLoading && <Loader2 className="animate-spin text-blue-400" size={24} />}
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
+6 -2
View File
@@ -1,11 +1,12 @@
import { useState } from 'react'
import { Loader2 } from 'lucide-react'
import { useProxyHosts } from '../hooks/useProxyHosts'
import type { ProxyHost } from '../api/proxyHosts'
import ProxyHostForm from '../components/ProxyHostForm'
import { Switch } from '../components/ui/Switch'
export default function ProxyHosts() {
const { hosts, loading, error, createHost, updateHost, deleteHost } = useProxyHosts()
const { hosts, loading, isFetching, error, createHost, updateHost, deleteHost } = useProxyHosts()
const [showForm, setShowForm] = useState(false)
const [editingHost, setEditingHost] = useState<ProxyHost | undefined>()
@@ -42,7 +43,10 @@ export default function ProxyHosts() {
return (
<div className="p-8">
<div className="flex items-center justify-between mb-6">
<h1 className="text-3xl font-bold text-white">Proxy Hosts</h1>
<div className="flex items-center gap-3">
<h1 className="text-3xl font-bold text-white">Proxy Hosts</h1>
{isFetching && !loading && <Loader2 className="animate-spin text-blue-400" size={24} />}
</div>
<button
onClick={handleAdd}
className="px-4 py-2 bg-blue-active hover:bg-blue-hover text-white rounded-lg font-medium transition-colors"
+6 -2
View File
@@ -1,10 +1,11 @@
import { useState } from 'react'
import { Loader2 } from 'lucide-react'
import { useRemoteServers } from '../hooks/useRemoteServers'
import type { RemoteServer } from '../api/remoteServers'
import RemoteServerForm from '../components/RemoteServerForm'
export default function RemoteServers() {
const { servers, loading, error, createServer, updateServer, deleteServer } = useRemoteServers()
const { servers, loading, isFetching, error, createServer, updateServer, deleteServer } = useRemoteServers()
const [showForm, setShowForm] = useState(false)
const [editingServer, setEditingServer] = useState<RemoteServer | undefined>()
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
@@ -42,7 +43,10 @@ export default function RemoteServers() {
return (
<div className="p-8">
<div className="flex items-center justify-between mb-6">
<h1 className="text-3xl font-bold text-white">Remote Servers</h1>
<div className="flex items-center gap-3">
<h1 className="text-3xl font-bold text-white">Remote Servers</h1>
{isFetching && !loading && <Loader2 className="animate-spin text-blue-400" size={24} />}
</div>
<div className="flex gap-3">
<div className="flex bg-gray-800 rounded-lg p-1">
<button