Skip to content
Snippets Groups Projects
Commit 865a3c49 authored by Imre Toth's avatar Imre Toth
Browse files

Merge branch 'ICSHWI-9271_Updating_host_details_page' into 'develop'

Icshwi 9271 updating host details page

See merge request !170
parents 0fc2df0d cfc17989
No related branches found
No related tags found
4 merge requests!270Merging develop branch to master in order to create RC,!222Fixing missing time interval parameter for logs,!202Merging develop to master,!170Icshwi 9271 updating host details page
Pipeline #112286 passed
......@@ -5,32 +5,32 @@ import { Typography } from "@material-ui/core";
export function formatToList(items) {
if(!items) return null;
return (
<ul style={{ padding: 0 }}>
{items.map((item) => (
<li style={{ listStylePosition: 'inside' }} key={item}>{item}</li>
))}
</ul>
)
if (!items) return null;
return (
<ul style={{ padding: 0 }}>
{items.map((item) => (
<li style={{ listStylePosition: 'inside' }} key={item}>{item}</li>
))}
</ul>
)
}
export function searchInArray(array, searchText) {
if(array) {
const found = array.find(element => element.toLowerCase().includes(searchText) );
if (array) {
const found = array.find(element => element.toLowerCase().includes(searchText));
return found;
}
return found;
}
return false;
return false;
}
export const formatDate = (value) => {
if (value) {
return moment(value).format('DD/MM/YYYY HH:mm:ss');
}
return null;
if (value) {
return moment(value).format('DD/MM/YYYY HH:mm:ss');
}
return null;
}
export const formatDateOnly = (value) => {
......@@ -65,9 +65,9 @@ export function useWindowDimensions() {
}, []);
return windowDimensions;
}
}
export function circularPalette(palette, index, opacity=1.0) {
export function circularPalette(palette, index, opacity = 1.0) {
const colors = Object.values(palette);
let n = colors.length;
return alpha(colors[(index % n + n) % n], opacity);
......@@ -76,7 +76,7 @@ export function circularPalette(palette, index, opacity=1.0) {
export function applicationSubTitle() {
const title = `${window.ENVIRONMENT_TITLE}`;
if((title) && (title !== 'undefined')) {
if ((title) && (title !== 'undefined')) {
return ' - ' + title;
}
......@@ -85,15 +85,15 @@ export function applicationSubTitle() {
export function initRequestParams(lazyParams, filter, columnSort) {
let requestParams = {
page: lazyParams.page,
page: lazyParams.page,
limit: lazyParams.rows
}
if ((filter != null) && filter) {
requestParams.query = filter;
}
if(columnSort) {
if(columnSort.sortOrder === 1) {
if (columnSort) {
if (columnSort.sortOrder === 1) {
requestParams.isAsc = true;
} else {
requestParams.isAsc = false;
......@@ -107,11 +107,11 @@ export const compareArrays = (a1, a2) =>
a1.length === a2.length &&
a1.every(
(element, index) => element === a2[index]
);
);
function createPartQuery(part, openEnd) {
if (part && part.length > 0) {
return "(+fqdn:" + part + (openEnd ? "*)" :")");
return "(+fqdn:" + part + (openEnd ? "*)" : ")");
}
return null;
}
......@@ -122,7 +122,7 @@ function joinParts(parts, openEnd) {
}
export function transformHostQuery(query) {
if(!query || query.length === 0) {
if (!query || query.length === 0) {
return null;
}
......@@ -130,9 +130,9 @@ export function transformHostQuery(query) {
if (parts.length === 1) {
return "fqdn:" + query + "*";
}
// if query ends with "-"
if (parts[parts.length - 1].length === 0 ) {
if (parts[parts.length - 1].length === 0) {
if (parts.length === 2) {
return "fqdn:" + parts[0];
}
......@@ -145,3 +145,18 @@ export function transformHostQuery(query) {
export function noWrapText(text) {
return <Typography noWrap>{text}</Typography>;
}
export function extractMainNetwork(interfaces, defaultReturn = "") {
if (!interfaces) {
return defaultReturn;
}
var i;
for (i = 0; i < interfaces.length; i++) {
if (interfaces[i]?.is_main) {
return interfaces[i].network;
}
}
return defaultReturn;
}
import React from "react";
import { IconBadge } from "../common/Badge/IconBadge";
import { HostStatusIcon } from "./HostIcons";
import { extractMainNetwork } from "../common/Helper";
export function HostBadge({ host }) {
console.log(host);
return (
<IconBadge icon={<HostStatusIcon host={host} />} title={host.csEntryHost?.fqdn} subheader={host.csEntryHost?.network || "---"} />
<IconBadge icon={<HostStatusIcon host={host} />} title={host.csEntryHost?.fqdn} subheader={ extractMainNetwork(host?.csEntryHost?.interfaces, "---")} />
)
}
\ No newline at end of file
import React, { useState } from 'react';
import {
Checkbox,
Table,
TableBody,
TableCell,
Button,
Grid,
Link,
Paper,
TableRow,
TableContainer
} from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import { TableHead } from '@material-ui/core';
import { formatToList } from '../common/Helper';
export default function HostInterfaces() {
//demo dummy data
let tmpIntF = [{
name: 'test.host.esss.lu.se',
isMain: false,
description: 'this is a test host',
cnames: [],
ip: '127.0.0.1',
mac: '12:58:34:bc:ef:a1',
network: { name: 'One network', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
},
{
name: 'test5.esss.lab.lu.se',
isMain: false,
description: 'a lab equipment host',
cnames: ['labnet', 'cnet'],
ip: '16.32.54.2',
mac: '9b:e5:ff:3a:bb:c0',
network: { name: 'Another network', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
},
{
name: 'technetwork.host.com',
isMain: false,
description: 'tester thing',
cnames: ['tst123'],
ip: '192.168.3.5',
mac: '71:bc:3a:de:b2:11',
network: { name: 'Network for Tests', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
},
{
name: 'prod.network.esss.lu.se',
isMain: true,
description: 'this is the prod env',
cnames: ['prod'],
ip: '172.18.4.22',
mac: 'ac:52:f2:4e:cc:21',
network: { name: 'Prod network', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
}
];
const [interfaces, setInterfaces] = useState(null);
//fill state with the dummy data
const testFillData = () => {
setInterfaces(tmpIntF);
}
//stlyes
//teble header
const StyledTableCell = withStyles((theme) => ({
head: {
backgroundColor: '#e0e0e0',
color: theme.palette.common.black,
fontWeight: 'bold',
},
body: {
fontSize: 14,
},
}))(TableCell);
//table body
const StyledTableRow = withStyles((theme) => ({
root: {
'&:nth-of-type(odd)': {
backgroundColor: '#e3f2fd',
},
},
}))(TableRow);
return (
<Grid container>
<Grid item xs={12} sm={6} md={8} lg={12}>
<Button variant="contained" color="primary" onClick={testFillData}>Load Data</Button>
<TableContainer component={Paper}>
<Table size="small" key="CSEntryInterfacesTable">
<TableHead>
<TableRow>
<StyledTableCell >Name</StyledTableCell>
<StyledTableCell >Network</StyledTableCell>
<StyledTableCell >IP</StyledTableCell>
<StyledTableCell >Description</StyledTableCell>
<StyledTableCell >CNames</StyledTableCell>
<StyledTableCell >Is Main?</StyledTableCell>
<StyledTableCell >Mac</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{interfaces?.map((row) => (
<StyledTableRow align="left" key={row.name}>
<TableCell >{row.name}</TableCell>
<TableCell >
<Link href={row.network.link} target="_blank" rel="noreferrer">
{row.network.name}
</Link>
</TableCell>
<TableCell >{row.ip}</TableCell>
<TableCell >{row.description}</TableCell>
<TableCell >{formatToList(row.cnames)}</TableCell>
<TableCell >
<Checkbox disabled checked={row.isMain} name="isIocCheckBox" />
</TableCell>
<TableCell >{row.mac}</TableCell>
</StyledTableRow>
)
)}
</TableBody>
</Table>
</TableContainer>
</Grid>
</Grid>
);
}
\ No newline at end of file
import React, { useState } from 'react';
import {
Accordion,
AccordionDetails,
AccordionSummary,
Link,
ListItemText,
Paper,
List,
Typography,
Table,
TableBody,
TableCell,
TableContainer,
TableRow,
Grid,
ListItem,
ListItemIcon
} from "@material-ui/core";
import { withStyles } from '@material-ui/core/styles';
import { formatToList } from '../common/Helper';
import { makeStyles } from '@material-ui/core/styles';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import Grade from '@material-ui/icons/Grade';
//demo dummy data
let tmpIntF = [{
id: 0,
name: 'test.host.esss.lu.se',
isMain: true,
description: 'this is a test host',
cnames: [],
ip: '127.0.0.1',
mac: '12:58:34:bc:ef:a1',
network: { name: 'One network', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
},
{
id: 1,
name: 'test5.esss.lab.lu.se',
isMain: false,
description: 'a lab equipment host',
cnames: ['labnet', 'cnet'],
ip: '16.32.54.2',
mac: '9b:e5:ff:3a:bb:c0',
network: { name: 'Another network', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
},
{
id: 2,
name: 'technetwork.host.com',
isMain: false,
description: 'tester thing',
cnames: ['tst123'],
ip: '192.168.3.5',
mac: '71:bc:3a:de:b2:11',
network: { name: 'Network for Tests', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
},
{
id: 3,
name: 'prod.network.esss.lu.se',
isMain: false,
description: 'this is the prod env',
cnames: ['prod'],
ip: '172.18.4.22',
mac: 'ac:52:f2:4e:cc:21',
network: { name: 'Prod network', link: 'https://csentry.esss.lu.se/network/hosts/view/mpsid-ipc-01' }
}
];
//stlyes
//table body
const StyledTableRow = withStyles((theme) => ({
root: {
'&:nth-of-type(odd)': {
backgroundColor: '#e3f2fd',
},
},
}))(TableRow);
//accordion
const useStyles = makeStyles((theme) => ({
parentWrapper: {
width: '100%',
'&> :nth-child(odd)':{
'&>div':{
backgroundColor: theme.palette.action.hover
}
},
},
}));
export function itemIcon({ isMain }) {
return isMain ? <Grade /> : null;
}
export function listItem(interFace) {
return (interFace.isMain ?
<ListItemText primary={<Typography variant="h6" inset="true"
style={{ fontWeight: 'bold', textShadow: '2px 2px 3px' }}>{interFace.name}</Typography>}
secondary={<Typography
style={{ fontWeight: 'bold', textShadow: '2px 2px 3px'}}>{interFace.network.name}</Typography>}></ListItemText> :
<ListItemText primary={interFace.name}
secondary={interFace.network.name} ></ListItemText>);
}
export default function InterfaceAccordion() {
const [interfaces] = useState(tmpIntF);
const classes = useStyles();
return (
<Grid container direction="column">
<Grid item xs={12} sm={6} md={12} className={classes.parentWrapper}>
{interfaces?.map((interFace, index) => (
<Accordion square key={interFace.id}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<List>
<ListItem>
<ListItemIcon>
{itemIcon(interFace)}
</ListItemIcon>
{listItem(interFace)}
</ListItem>
</List>
</AccordionSummary>
<AccordionDetails>
<TableContainer component={Paper}>
<Table size="small">
<TableBody >
<StyledTableRow align="left" >
<TableCell ><strong>Network:</strong></TableCell>
<TableCell >
<Link href={interFace.network.link} target="_blank" rel="noreferrer">
{interFace.network.name}
</Link>
</TableCell>
</StyledTableRow>
<StyledTableRow align="left">
<TableCell ><strong>IP:</strong></TableCell>
<TableCell >{interFace.ip}</TableCell>
</StyledTableRow>
<StyledTableRow align="left">
<TableCell ><strong>Description:</strong></TableCell>
<TableCell >{interFace.description}</TableCell>
</StyledTableRow>
<StyledTableRow align="left">
<TableCell ><strong>CNames:</strong></TableCell>
<TableCell >{formatToList(interFace.cnames)}</TableCell>
</StyledTableRow>
<StyledTableRow align="left">
<TableCell ><strong>MAC:</strong></TableCell>
<TableCell >{interFace.mac}</TableCell>
</StyledTableRow>
</TableBody>
</Table>
</TableContainer>
</AccordionDetails>
</Accordion>
))}
</Grid>
</Grid>
);
}
\ No newline at end of file
......@@ -17,7 +17,7 @@ import { IOCAsyncList } from "../../components/IOC/IOCAsyncList";
import { KeyValueTable } from '../../components/common/KeyValueTable/KeyValueTable';
import { LokiPanel } from '../../components/common/Loki/LokiPanel';
import { useHistory } from "react-router-dom";
import { formatDate, initRequestParams } from '../../components/common/Helper';
import { initRequestParams } from '../../components/common/Helper';
import AccessControl from '../../components/auth/AccessControl';
import { useGlobalAppBar } from '../../components/navigation/GlobalAppBar/GlobalAppBar';
import { useHost } from "../../api/SwaggerApi";
......@@ -29,25 +29,25 @@ const useStyles = makeStyles((theme) => ({
},
}));
export function HostDetailsView({ id}) {
export function HostDetailsView({ id }) {
const [host] = useHost(id);
const [iocs, getIocs, /*reset*/, loading] = useHostIOCList();
const [deployedIocs, setDeployedIocs] = useState([]);
const history = useHistory();
const classes = useStyles();
const [lazyParams, setLazyParams] = useState({
first: 0,
rows: 5,
page: 0
});
const [columnSort, setColumnSort] = useState({
});
const [columnSort, setColumnSort] = useState({
sortField: null,
sortOrder: null
});
});
const rowsPerPage = [5, 20];
const rowsPerPage = [5, 20];
useEffect(() => {
let requestParams = initRequestParams(lazyParams, null, columnSort);
......@@ -61,14 +61,26 @@ export function HostDetailsView({ id}) {
setDeployedIocs(iocs?.deployedList ?? []);
}, [iocs, setDeployedIocs])
const renderHost = { ...host?.csEntryHost };
delete renderHost.id;
renderHost.interfaces = <pre>{JSON.stringify(host?.csEntryHost?.interfaces, null, 2)}</pre>;
renderHost.ansible_vars = <pre>{JSON.stringify(host?.csEntryHost?.ansible_vars, null, 2)}</pre>
renderHost.ansible_groups = <pre>{JSON.stringify(host?.csEntryHost?.ansible_groups, null, 2)}</pre>
const createdAt = renderHost.created_at;
delete renderHost.created_at;
renderHost["created at"] = formatDate(createdAt);
function listToString(list) {
if (list) {
if (Array.isArray(list)) {
return list.join(", ");
}
return list;
}
return "";
}
let renderHost = {
"registered by": host?.csEntryHost?.user,
"device type": host?.csEntryHost?.device_type,
description: host?.csEntryHost?.description,
scope: host?.csEntryHost?.scope,
"vm owner": listToString(host?.csEntryHost?.ansible_vars?.vm_owner),
"ansible groups": listToString(host?.csEntryHost?.ansible_groups)
}
const handleClick = (event) => {
history.goBack();
......@@ -80,17 +92,35 @@ export function HostDetailsView({ id}) {
host && host.csEntryHost && setTitle("Host Details: " + host.csEntryHost.name);
}, [host, setTitle]);
function accordionHeader() {
return (
<>
{host && <HostBadge host={host} />}
</>
)
}
return (
<Paper>
<IconButton color="inherit" onClick={handleClick}>
<ArrowBackIcon />
</IconButton>
{host && <HostBadge host={host} />}
{host && <AlertMessages alerts={host.alerts}/>}
{host && <AlertMessages alerts={host.alerts} />}
<SimpleAccordion defaultExpanded summary={accordionHeader()}>
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
renderNoAccess={() => <></>} >
{host && <KeyValueTable obj={renderHost} />}
</AccessControl>
</SimpleAccordion>
<SimpleAccordion summary="Deployed IOCs" defaultExpanded>
<IOCAsyncList iocs={deployedIocs} setIocs={setDeployedIocs} loading={loading} rowType="host"
<IOCAsyncList iocs={deployedIocs} setIocs={setDeployedIocs} loading={loading} rowType="host"
totalCount={iocs.totalCount} lazyParams={lazyParams} setLazyParams={setLazyParams} columnSort={columnSort} setColumnSort={setColumnSort}
rowsPerPage={rowsPerPage}/>
rowsPerPage={rowsPerPage} />
</SimpleAccordion>
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
renderNoAccess={() => <></>}>
......@@ -116,13 +146,6 @@ export function HostDetailsView({ id}) {
</Container>
</CardContent>
</Card>
<AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
renderNoAccess={() => <></>} >
<SimpleAccordion summary="CSEntry Configuration">
{host && <KeyValueTable obj={renderHost} variant="table" />}
</SimpleAccordion>
</AccessControl>
</Paper>
);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment