diff --git a/resources/scripts/api/admin/nodes/getNodes.ts b/resources/scripts/api/admin/nodes/getNodes.ts index 45a020f0..961fba1e 100644 --- a/resources/scripts/api/admin/nodes/getNodes.ts +++ b/resources/scripts/api/admin/nodes/getNodes.ts @@ -1,6 +1,7 @@ import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/api/http'; import { createContext, useContext } from 'react'; import useSWR from 'swr'; +import { Location, rawDataToLocation } from '@/api/admin/locations/getLocations'; export interface Node { id: number; @@ -23,6 +24,10 @@ export interface Node { daemonBase: string; createdAt: Date; updatedAt: Date; + + relations: { + location: Location | undefined; + }; } export const rawDataToNode = ({ attributes }: FractalResponseData): Node => ({ @@ -46,6 +51,10 @@ export const rawDataToNode = ({ attributes }: FractalResponseData): Node => ({ daemonBase: attributes.daemon_base, createdAt: new Date(attributes.created_at), updatedAt: new Date(attributes.updated_at), + + relations: { + location: attributes.relationships?.location !== undefined ? rawDataToLocation(attributes.relationships.location as FractalResponseData) : undefined, + }, }); interface ctx { @@ -55,11 +64,11 @@ interface ctx { export const Context = createContext({ page: 1, setPage: () => 1 }); -export default () => { +export default (include: string[] = []) => { const { page } = useContext(Context); return useSWR>([ 'nodes', page ], async () => { - const { data } = await http.get('/api/application/nodes', { params: { page } }); + const { data } = await http.get('/api/application/nodes', { params: { include: include.join(','), page } }); return ({ items: (data.data || []).map(rawDataToNode), diff --git a/resources/scripts/components/admin/nodes/NodesContainer.tsx b/resources/scripts/components/admin/nodes/NodesContainer.tsx index af77eb49..f7737c8d 100644 --- a/resources/scripts/components/admin/nodes/NodesContainer.tsx +++ b/resources/scripts/components/admin/nodes/NodesContainer.tsx @@ -9,6 +9,8 @@ import AdminContentBlock from '@/components/admin/AdminContentBlock'; import AdminCheckbox from '@/components/admin/AdminCheckbox'; import AdminTable, { TableBody, TableHead, TableHeader, TableRow, Pagination, Loading, NoItems, ContentWrapper } from '@/components/admin/AdminTable'; import Button from '@/components/elements/Button'; +import CopyOnClick from '@/components/elements/CopyOnClick'; +import { bytesToHuman, megabytesToBytes } from '@/helpers'; const RowCheckbox = ({ id }: { id: number}) => { const isChecked = AdminContext.useStoreState(state => state.nodes.selectedNodes.indexOf(id) >= 0); @@ -35,7 +37,7 @@ const NodesContainer = () => { const { page, setPage } = useContext(NodesContext); const { clearFlashes, clearAndAddHttpError } = useFlash(); - const { data: nodes, error, isValidating } = getNodes(); + const { data: nodes, error, isValidating } = getNodes([ 'location' ]); useEffect(() => { if (!error) { @@ -91,6 +93,11 @@ const NodesContainer = () => { + + + + + @@ -101,12 +108,51 @@ const NodesContainer = () => { - {node.id} + + + {node.id} + + + {node.name} + + {/* TODO: Have permission check for displaying location information. */} + + +
+ {node.relations.location?.short} +
+ +
+ {node.relations.location?.long} +
+
+ + + + + {node.fqdn} + + + + {bytesToHuman(megabytesToBytes(node.memory))} + {bytesToHuman(megabytesToBytes(node.disk))} + + + { node.scheme === 'https' ? + + Secure + + : + + Non-Secure + + } + )) }