1- import React , { useEffect , useState } from 'react' ;
2- import tw from 'twin.macro' ;
3- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' ;
4- import { faNetworkWired } from '@fortawesome/free-solid-svg-icons' ;
5- import styled from 'styled-components/macro' ;
6- import GreyRowBox from '@/components/elements/GreyRowBox' ;
7- import Button from '@/components/elements/Button' ;
8- import Can from '@/components/elements/Can' ;
1+ import React , { useCallback , useEffect } from 'react' ;
92import useSWR from 'swr' ;
103import getServerAllocations from '@/api/server/network/getServerAllocations' ;
114import { Allocation } from '@/api/server/getServer' ;
125import Spinner from '@/components/elements/Spinner' ;
13- import setPrimaryServerAllocation from '@/api/server/network/setPrimaryServerAllocation' ;
146import useFlash from '@/plugins/useFlash' ;
15- import { Textarea } from '@/components/elements/Input' ;
16- import setServerAllocationNotes from '@/api/server/network/setServerAllocationNotes' ;
17- import { debounce } from 'debounce' ;
18- import InputSpinner from '@/components/elements/InputSpinner' ;
197import ServerContentBlock from '@/components/elements/ServerContentBlock' ;
208import { ServerContext } from '@/state/server' ;
219import { useDeepMemoize } from '@/plugins/useDeepMemoize' ;
22-
23- const Code = styled . code `${ tw `font-mono py-1 px-2 bg-neutral-900 rounded text-sm block` } ` ;
24- const Label = styled . label `${ tw `uppercase text-xs mt-1 text-neutral-400 block px-1 select-none transition-colors duration-150` } ` ;
10+ import AllocationRow from '@/components/server/network/AllocationRow' ;
11+ import setPrimaryServerAllocation from '@/api/server/network/setPrimaryServerAllocation' ;
2512
2613const NetworkContainer = ( ) => {
2714 const uuid = ServerContext . useStoreState ( state => state . server . data ! . uuid ) ;
2815 const allocations = useDeepMemoize ( ServerContext . useStoreState ( state => state . server . data ! . allocations ) ) ;
2916
3017 const { clearFlashes, clearAndAddHttpError } = useFlash ( ) ;
31- const [ loading , setLoading ] = useState < false | number > ( false ) ;
32- const { data, error, mutate } = useSWR < Allocation [ ] > ( uuid , key => getServerAllocations ( key ) , { initialData : allocations } ) ;
18+ const { data, error, mutate } = useSWR < Allocation [ ] > ( uuid , key => getServerAllocations ( key ) , {
19+ initialData : allocations ,
20+ revalidateOnFocus : false ,
21+ } ) ;
22+
23+ useEffect ( ( ) => {
24+ if ( error ) {
25+ clearAndAddHttpError ( { key : 'server:network' , error } ) ;
26+ }
27+ } , [ error ] ) ;
3328
34- const setPrimaryAllocation = ( id : number ) => {
29+ const setPrimaryAllocation = useCallback ( ( id : number ) => {
3530 clearFlashes ( 'server:network' ) ;
3631
3732 const initial = data ;
@@ -42,77 +37,24 @@ const NetworkContainer = () => {
4237 clearAndAddHttpError ( { key : 'server:network' , error } ) ;
4338 mutate ( initial , false ) ;
4439 } ) ;
45- } ;
40+ } , [ ] ) ;
4641
47- const setAllocationNotes = debounce ( ( id : number , notes : string ) => {
48- setLoading ( id ) ;
49- clearFlashes ( 'server:network' ) ;
50-
51- setServerAllocationNotes ( uuid , id , notes )
52- . then ( ( ) => mutate ( data ?. map ( a => a . id === id ? { ...a , notes } : a ) , false ) )
53- . catch ( error => {
54- clearAndAddHttpError ( { key : 'server:network' , error } ) ;
55- } )
56- . then ( ( ) => setLoading ( false ) ) ;
57- } , 750 ) ;
58-
59- useEffect ( ( ) => {
60- if ( error ) {
61- clearAndAddHttpError ( { key : 'server:network' , error } ) ;
62- }
63- } , [ error ] ) ;
42+ const onNotesAdded = useCallback ( ( id : number , notes : string ) => {
43+ mutate ( data ?. map ( a => a . id === id ? { ...a , notes } : a ) , false ) ;
44+ } , [ ] ) ;
6445
6546 return (
6647 < ServerContentBlock showFlashKey = { 'server:network' } title = { 'Network' } >
6748 { ! data ?
6849 < Spinner size = { 'large' } centered />
6950 :
70- data . map ( ( { id, ip, port, alias, notes, isDefault } , index ) => (
71- < GreyRowBox
72- $hoverable = { false }
73- key = { `${ ip } :${ port } ` }
74- css = { index > 0 ? tw `mt-2 overflow-x-auto` : tw `overflow-x-auto` }
75- >
76- < div css = { tw `hidden md:block pl-4 pr-6 text-neutral-400` } >
77- < FontAwesomeIcon icon = { faNetworkWired } />
78- </ div >
79- < div css = { tw `mr-4` } >
80- < Code > { alias || ip } </ Code >
81- < Label > IP Address</ Label >
82- </ div >
83- < div >
84- < Code > { port } </ Code >
85- < Label > Port</ Label >
86- </ div >
87- < div css = { tw `px-8 flex-none sm:flex-1 self-start` } >
88- < InputSpinner visible = { loading === id } >
89- < Textarea
90- css = { tw `bg-neutral-800 hover:border-neutral-600 border-transparent` }
91- placeholder = { 'Notes' }
92- defaultValue = { notes || undefined }
93- onChange = { e => setAllocationNotes ( id , e . currentTarget . value ) }
94- />
95- </ InputSpinner >
96- </ div >
97- < div css = { tw `w-32 text-right pr-4 sm:pr-0` } >
98- { isDefault ?
99- < span css = { tw `bg-green-500 py-1 px-2 rounded text-green-50 text-xs` } >
100- Primary
101- </ span >
102- :
103- < Can action = { 'allocations.update' } >
104- < Button
105- isSecondary
106- size = { 'xsmall' }
107- color = { 'primary' }
108- onClick = { ( ) => setPrimaryAllocation ( id ) }
109- >
110- Make Primary
111- </ Button >
112- </ Can >
113- }
114- </ div >
115- </ GreyRowBox >
51+ data . map ( allocation => (
52+ < AllocationRow
53+ key = { `${ allocation . ip } :${ allocation . port } ` }
54+ allocation = { allocation }
55+ onSetPrimary = { setPrimaryAllocation }
56+ onNotesChanged = { onNotesAdded }
57+ />
11658 ) )
11759 }
11860 </ ServerContentBlock >
0 commit comments