diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js index 8cec23d7dc054df7ed96af35959f1d51e87ff08c..87d7c29b07ac2f664831720501ab387d81ff2a30 100644 --- a/src/api/SwaggerApi.js +++ b/src/api/SwaggerApi.js @@ -2,7 +2,7 @@ import SwaggerClient from 'swagger-client'; import { createContext, useContext, useEffect, useState } from "react"; import { CircularProgress } from '@material-ui/core'; -const SERVER = `https://${window.location.hostname}/api`; // development server +const SERVER = `https://${window.location.hostname}/api`; // current domain const TOKEN = "ccce"; // development token // Here is some hardcoded garbage to test the openapi spec @@ -68,7 +68,7 @@ function callAndUnpack(fcn, unpacker = x => x) { export function unpackIOC(ioc) { console.log(ioc); ioc = { ...ioc }; - const { id, customName, description, owner, createdBy, status, configuredToHost, latestVersion, activeDeployments } = ioc; + const { id, customName, description, owner, createdBy, active, configuredToHost, latestVersion, activeDeployments } = ioc; const activeDeployment = (activeDeployments && activeDeployments.length) ? activeDeployments[0] : null; const deployedVersion = activeDeployment ? activeDeployment.version : null; @@ -86,13 +86,15 @@ export function unpackIOC(ioc) { activeDeployment: activeDeployment, deployedVersion: deployedVersion, latestHost: configuredToHost, + active: active, + status: configuredToHost.status, }; if (unpackedIOC.latestHost) unpackedIOC.host = unpackedIOC.latestHost.host; if (inflated) { const getSubset = (v) => { - return { git: v.sourceUrl, version: v.sourceVersion, status: "ok" } + return { git: v.sourceUrl, version: v.sourceVersion } }; const subset = getSubset(inflated); unpackedIOC = Object.assign(unpackedIOC, subset); @@ -136,14 +138,15 @@ export function useUpdateIOC(id) { } export function unpackDeployment(deployment) { - const d = {...deployment}; + const d = { ...deployment }; d.status = "success"; console.log(d); return d; } export function unpackDeploymentList(deployments) { - return deployments.map(d => unpackDeployment(d)); + console.log(deployments); + return deployments.deployments.map(d => unpackDeployment(d)); } export function useDeploymentList() { @@ -158,6 +161,29 @@ export function useDeployment(id) { return useAsync({ fcn: method.bind(null, { deploymentId: id }) }); } +export function useCreateDeployment() { + const api = useContext(apiContext); + const method = callAndUnpack( + (iocs, comment = "") => api.apis.Deployments.createDeployment({}, { requestBody: { iocIds: iocs.map((ioc) => ioc.id), comment: comment } }), + unpackDeployment + ); + return useAsync({ fcn: method, call: false }); +} + +export function unpackHost(host) { + return { ...host }; +} + +export function unpackHostList(hosts) { + return hosts.hostList.map(h => unpackHost(h)); +} + +export function useHostList() { + const api = useContext(apiContext); + const method = callAndUnpack(api.apis.Hosts.listAvailableHosts, unpackHostList) + return useAsync({ fcn: method, init: [] }); +} + export function useAPI() { const createSwaggerClient = async () => { const swagger = await SwaggerClient(swaggerOptions) diff --git a/src/components/IOC/IOCConfiguration.js b/src/components/IOC/IOCConfiguration.js index bc1cf0ac9ae57f47e46572db5c1be3c1ae2f32fc..30f370ce89c06f3cd1050a6282e8134550f4c95e 100644 --- a/src/components/IOC/IOCConfiguration.js +++ b/src/components/IOC/IOCConfiguration.js @@ -1,16 +1,20 @@ -import { Box, Button, Container, IconButton, useTheme } from "@material-ui/core"; +import { Box, Button, Container, Fab, IconButton, useTheme } from "@material-ui/core"; import { DirectionsBoat, Edit } from "@material-ui/icons"; import React, { useState } from "react"; import { useGlobalAppBar } from "../../components/navigation/GlobalAppBar/GlobalAppBar"; import { IOCDetails } from "../../components/IOC/IOCDetails"; import { CreateIOC } from "../../components/IOC/CreateIOC"; import { SimpleModal } from "../../components/common/SimpleModal/SimpleModal"; -import { useIOC, useUpdateIOC } from "../../api/SwaggerApi"; +import { useCreateDeployment, useIOC, useUpdateIOC } from "../../api/SwaggerApi"; import { KeyValueTable } from "../../components/common/KeyValueTable/KeyValueTable"; +import { useHistory } from "react-router-dom"; export function IOCConfiguration({ ioc }) { const [iocFormOpen, setIOCFormOpen] = useState(false); + const [deployment, createDeployment] = useCreateDeployment(); const theme = useTheme(); + const history = useHistory() + useGlobalAppBar( "IOC Details", <IconButton onClick={() => { setIOCFormOpen(true) }}> @@ -20,12 +24,12 @@ export function IOCConfiguration({ ioc }) { const closeModal = () => { setIOCFormOpen(false); - // getIOC(); + history.go(0); } let content = <></>; - if (ioc) { - const getSubset = ({name, description, host, status}) => ({name, description, host, status}); + if (ioc) { + const getSubset = ({ name, description, host, active, status }) => ({ name, description, host, active, status }); const ioc2 = getSubset(ioc) console.log(ioc2); delete ioc2.activeDeployment; @@ -45,16 +49,17 @@ export function IOCConfiguration({ ioc }) { <IOCDetails ioc={ioc2} /> </Container> { - // (ioc.host && ioc.status === "undeployed") && - // <Fab color="secondary" variant="extended" style={{ - // position: "fixed", - // bottom: "2%", - // left: "50%", - // /* bring your own prefixes */ - // transform: "translate(-50%, -50%)" - // }}> - // DEPLOY CHANGES - // </Fab> + (ioc && ioc.host) && + <Fab color="secondary" variant="extended" style={{ + position: "fixed", + bottom: "2%", + left: "50%", + /* bring your own prefixes */ + transform: "translate(-50%, -50%)" + }} + onClick={() => { createDeployment([ioc], "triggered from a button") }}> + DEPLOY THIS VERSION + </Fab> } <SimpleModal open={iocFormOpen} setOpen={setIOCFormOpen}> <CreateIOC submitCallback={closeModal} init={ioc} hook={useUpdateIOC.bind(null, ioc.id)} /> diff --git a/src/components/IOC/IOCForm.js b/src/components/IOC/IOCForm.js index f2f2d26466283e282ec456c2495446b21eb35c1c..8b1cd17364f86166d0ee80ca5f31548891775b72 100644 --- a/src/components/IOC/IOCForm.js +++ b/src/components/IOC/IOCForm.js @@ -1,23 +1,37 @@ -import React from "react"; +import React, { useState } from "react"; import { Button, TextField } from "@material-ui/core"; +import { Autocomplete } from "@material-ui/lab"; +import { useHostList } from "../../api/SwaggerApi"; -export function IOCForm({submitCallback, init={}}) { - const onSubmit = (event) => { +export function IOCForm({ submitCallback, init = {} }) { + const [hosts] = useHostList(); + const [host, setHost] = useState(null); + + const onSubmit = (event) => { event.preventDefault(); - const {name: nameText, git: gitText, version: versionText, host: hostText} = event.currentTarget.elements; + const { name: nameText, description: descriptionText, git: gitText, version: versionText, host: hostText } = event.currentTarget.elements; const name = nameText.value; + const description = descriptionText.value; const git = gitText.value; const version = versionText.value; - const host = hostText.value; - submitCallback({customName: name, description: "dummy", owner: "dummyOwner", sourceUrl: git, sourceVersion: version, hostId: parseInt(host)}); + console.log(host); + submitCallback({ customName: name, description: description, owner: "dummyOwner", sourceUrl: git, sourceVersion: version, hostId: parseInt(host.id) }); }; return ( <form onSubmit={onSubmit}> <TextField autoComplete="off" required id="name" label="name" variant="outlined" defaultValue={init.name || ""} fullWidth /> + <TextField autoComplete="off" required id="description" label="description" variant="outlined" defaultValue={init.description || ""} fullWidth /> <TextField autoComplete="off" required id="git" label="git" variant="outlined" defaultValue={init.git || ""} fullWidth /> <TextField autoComplete="off" required id="version" label="version" variant="outlined" defaultValue={init.version || ""} fullWidth /> - <TextField autoComplete="off" id = "host" label="host (optional)" variant="outlined" defaultValue={init.host || ""} fullWidth /> + {/* <TextField autoComplete="off" id = "host" label="host (optional)" variant="outlined" defaultValue={init.host || ""} fullWidth /> */} + <Autocomplete + id="host" + options={hosts} + getOptionLabel={option => option.host} + renderInput={(params) => <TextField {...params} required label="host" variant="outlined" />} + onChange={(event, value, reason) => setHost(value)} + /> <Button variant="contained" color="primary" fullWidth type="submit">Create</Button> </form> ); diff --git a/src/components/IOC/IOCIcons.js b/src/components/IOC/IOCIcons.js index 9e2cb06015e75a4c19855687c73b60b8bc41abb0..a66942eb84eefd641a62821de43a64b3aeaf2339 100644 --- a/src/components/IOC/IOCIcons.js +++ b/src/components/IOC/IOCIcons.js @@ -6,22 +6,36 @@ export function IOCStatusIcon({ ioc }) { const theme = useTheme(); + // const statusBulbColors = { + // "ok": theme.palette.success.light, + // "down": theme.palette.text.disabled, + // "unreachable": theme.palette.secondary.light, + // "undeployed": theme.palette.text.disabled, + // }; + + // const statusBulbIcons = { + // "ok": <Brightness1 />, + // "down": <Brightness1 />, + // "unreachable": <ErrorOutline />, + // "undeployed": <RadioButtonUnchecked />, + // } + const statusBulbColors = { - "ok": theme.palette.success.light, - "down": theme.palette.text.disabled, - "unreachable": theme.palette.secondary.light, - "undeployed": theme.palette.text.disabled, + true: theme.palette.success.light, + false: theme.palette.text.disabled, + null: theme.palette.text.disabled, }; const statusBulbIcons = { - "ok": <Brightness1 />, - "down": <Brightness1 />, - "unreachable": <ErrorOutline />, - "undeployed": <RadioButtonUnchecked />, + true: <Brightness1 />, + false: <Brightness1 />, + null: <RadioButtonUnchecked />, } + + console.log(ioc); - const iconStyle = { fill: statusBulbColors[ioc.status] }; - const icon = React.cloneElement(statusBulbIcons[ioc.status], { style: iconStyle }); + const iconStyle = { fill: statusBulbColors[ioc.active] }; + const icon = React.cloneElement(statusBulbIcons[ioc.active], { style: iconStyle }); return icon; } diff --git a/src/components/host/Hosts.js b/src/components/host/Hosts.js index 26b1fb6d8c2e091aadd99aa2245b473665db181b..fd023e399368fc2863083bba0e42e8565567f469 100644 --- a/src/components/host/Hosts.js +++ b/src/components/host/Hosts.js @@ -5,72 +5,88 @@ import HostTable from './HostTable'; import HostList from './HostList'; import { Paper, - Grid + Grid, + Hidden } from '@material-ui/core'; +import { useHostList } from '../../api/SwaggerApi'; let demoHosts = [ - { id: 0, network: 'cslab.esss.lu.se', host: 'ds2.cslab.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'Test description', - createdby: 'krisztianloki', createdat: '2018-12-05', vmowners: ['krisztianloki', 'johndoe'], ansiblevar: ['csentry_vm_cores: 2', 'csentry_vm_memory: 2048', - 'proxmox_disk_space: 15'] }, - { id: 1, network: 'cslab.esss.lu.se', host: 'swcdev01.cslab.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'Crated for testing', - createdby: 'georgelucas', createdat: '2018-12-05', vmowners: ['georgelucas'], ansiblevar: ['csentry_vm_cores: 6', 'csentry_vm_memory: 4096'] }, - { id: 2, network: 'cslab.esss.lu.se', host: 'test01.cslab.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'This is a CSLab host', - createdby: 'anakin', createdat: '2018-12-05', vmowners: ['anakin', 'mcfly'], ansiblevar: ['csentry_vm_cores: 1', 'csentry_vm_memory: 8096', - 'proxmox_disk_space: 5'] }, - { id: 3, network: 'tn.esss.lu.se', host: 'amirvm-01.tn.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'Test lab equipment', - createdby: 'miklosboros', createdat: '2018-12-05', vmowners: ['miklosboros'], ansiblevar: ['proxmox_disk_space: 10'] }, - { id: 4, network: 'esss.lu.se', host: 'testcentos76.tn.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'No further description', - createdby: 'krisztianloki', createdat: '2018-12-05', vmowners: ['krisztianloki'], ansiblevar: ['csentry_vm_cores: 4', 'csentry_vm_memory: 3058', - 'proxmox_disk_space: 2'] }, - { id: 5, network: 'esss.lu.se', host: 'production.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'Test description', - createdby: 'anders', createdat: '2018-12-05', vmowners: ['anders', 'janake'], ansiblevar: ['csentry_vm_cores: 2'] }, - { id: 6, network: 'esss.lu.se', host: 'staging.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'Test description', - createdby: 'janedoe', createdat: '2018-12-05', vmowners: ['janedoe', 'anders', 'anakin'], ansiblevar: ['csentry_vm_memory: 4096'] }, - { id: 7, network: 'esss.lu.se', host: 'e3.server.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'Production host', - createdby: 'miklosboros', createdat: '2018-12-05', vmowners: ['miklosboros', 'joao'], ansiblevar: ['csentry_vm_memory: 2048', - 'proxmox_disk_space: 10'] }, - { id: 8, network: 'test.network.eu', host: 'cryo.lab.test.network.eu', isioc: true, devicetype: 'Virtual', description: 'Test description', - createdby: 'johnsnow', createdat: '2018-12-05', vmowners: ['johnsnow', 'arya', 'hodor'], ansiblevar: ['csentry_vm_cores: 4','proxmox_disk_space: 150']}, - { id: 9, network: 'test.network.eu', host: 'ncl.labs.test.network.eu', isioc: false, devicetype: 'Virtual', description: 'Test description', - createdby: 'hodor', createdat: '2018-12-05', vmowners: ['hodor'], ansiblevar: ['csentry_vm_cores: 3', 'csentry_vm_memory: 6048', - 'proxmox_disk_space: 10']}, - { id: 10, network: 'test.network.eu', host: 'ioclab.test.network.eu', isioc: true, devicetype: 'Virtual', description: 'Lorem ipsum', - createdby: 'johnsnow', createdat: '2018-12-05', vmowners: ['johnsnow', 'johndoe'], ansiblevar: ['csentry_vm_cores: 4']}, - { id: 11, network: 'test.network.eu', host: 'e3env.test.network.eu', isioc: true, devicetype: 'Virtual', description: 'Test description', - createdby: 'emmettbrown', createdat: '2018-12-05', vmowners: ['emmettbrown', 'stanlee'], ansiblevar: ['csentry_vm_cores: 1', 'csentry_vm_memory: 6098'] } + { + id: 0, network: 'cslab.esss.lu.se', host: 'ds2.cslab.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'Test description', + createdby: 'krisztianloki', createdat: '2018-12-05', vmowners: ['krisztianloki', 'johndoe'], ansiblevar: ['csentry_vm_cores: 2', 'csentry_vm_memory: 2048', + 'proxmox_disk_space: 15'] + }, + { + id: 1, network: 'cslab.esss.lu.se', host: 'swcdev01.cslab.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'Crated for testing', + createdby: 'georgelucas', createdat: '2018-12-05', vmowners: ['georgelucas'], ansiblevar: ['csentry_vm_cores: 6', 'csentry_vm_memory: 4096'] + }, + { + id: 2, network: 'cslab.esss.lu.se', host: 'test01.cslab.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'This is a CSLab host', + createdby: 'anakin', createdat: '2018-12-05', vmowners: ['anakin', 'mcfly'], ansiblevar: ['csentry_vm_cores: 1', 'csentry_vm_memory: 8096', + 'proxmox_disk_space: 5'] + }, + { + id: 3, network: 'tn.esss.lu.se', host: 'amirvm-01.tn.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'Test lab equipment', + createdby: 'miklosboros', createdat: '2018-12-05', vmowners: ['miklosboros'], ansiblevar: ['proxmox_disk_space: 10'] + }, + { + id: 4, network: 'esss.lu.se', host: 'testcentos76.tn.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'No further description', + createdby: 'krisztianloki', createdat: '2018-12-05', vmowners: ['krisztianloki'], ansiblevar: ['csentry_vm_cores: 4', 'csentry_vm_memory: 3058', + 'proxmox_disk_space: 2'] + }, + { + id: 5, network: 'esss.lu.se', host: 'production.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'Test description', + createdby: 'anders', createdat: '2018-12-05', vmowners: ['anders', 'janake'], ansiblevar: ['csentry_vm_cores: 2'] + }, + { + id: 6, network: 'esss.lu.se', host: 'staging.esss.lu.se', isioc: true, devicetype: 'Virtual', description: 'Test description', + createdby: 'janedoe', createdat: '2018-12-05', vmowners: ['janedoe', 'anders', 'anakin'], ansiblevar: ['csentry_vm_memory: 4096'] + }, + { + id: 7, network: 'esss.lu.se', host: 'e3.server.esss.lu.se', isioc: false, devicetype: 'Virtual', description: 'Production host', + createdby: 'miklosboros', createdat: '2018-12-05', vmowners: ['miklosboros', 'joao'], ansiblevar: ['csentry_vm_memory: 2048', + 'proxmox_disk_space: 10'] + }, + { + id: 8, network: 'test.network.eu', host: 'cryo.lab.test.network.eu', isioc: true, devicetype: 'Virtual', description: 'Test description', + createdby: 'johnsnow', createdat: '2018-12-05', vmowners: ['johnsnow', 'arya', 'hodor'], ansiblevar: ['csentry_vm_cores: 4', 'proxmox_disk_space: 150'] + }, + { + id: 9, network: 'test.network.eu', host: 'ncl.labs.test.network.eu', isioc: false, devicetype: 'Virtual', description: 'Test description', + createdby: 'hodor', createdat: '2018-12-05', vmowners: ['hodor'], ansiblevar: ['csentry_vm_cores: 3', 'csentry_vm_memory: 6048', + 'proxmox_disk_space: 10'] + }, + { + id: 10, network: 'test.network.eu', host: 'ioclab.test.network.eu', isioc: true, devicetype: 'Virtual', description: 'Lorem ipsum', + createdby: 'johnsnow', createdat: '2018-12-05', vmowners: ['johnsnow', 'johndoe'], ansiblevar: ['csentry_vm_cores: 4'] + }, + { + id: 11, network: 'test.network.eu', host: 'e3env.test.network.eu', isioc: true, devicetype: 'Virtual', description: 'Test description', + createdby: 'emmettbrown', createdat: '2018-12-05', vmowners: ['emmettbrown', 'stanlee'], ansiblevar: ['csentry_vm_cores: 1', 'csentry_vm_memory: 6098'] + } ] export default function Hosts() { - const [selectedTab, setSelectedTab] = useState(0); - const [content, setContent] = useState(<HostList demoHosts={demoHosts} />) + // const [selectedTab, setSelectedTab] = useState(0); + const [hosts] = useHostList(); - const handleTabChange = (event, tab) => { - - setSelectedTab(tab); + const content = ( + <> + <Hidden smUp> + <HostList demoHosts={hosts} /> + </Hidden> + <Hidden xsDown> + <HostTable demoHosts={hosts} /> + </Hidden> + </> + ); - if (tab === 0) { - setContent(<HostList demoHosts={demoHosts} />); - } - else if (tab === 1) { - setContent(<HostTable demoHosts={demoHosts} />); - } - }; return ( <Paper> <Grid container spacing={1} justify="flex-end"> - <Grid item xs={12} md={9}> - <Tabs - value={selectedTab} - onChange={handleTabChange} - indicatorColor="primary" - textColor="primary"> - <Tab label="Basic View" /> - <Tab label="Advanced View" /> - </Tabs> - </Grid> <Grid item xs={12} md={12}> {content} </Grid> diff --git a/src/views/IOC/IOCDetailsView.js b/src/views/IOC/IOCDetailsView.js index b7fd3f225ec4d9d1d8732ca87a30b857397c037f..482f2aef61ff224987557acf21cdf55c7b6d6b0e 100644 --- a/src/views/IOC/IOCDetailsView.js +++ b/src/views/IOC/IOCDetailsView.js @@ -1,4 +1,4 @@ -import { AccordionSummary, Box, Button, CardHeader, Container, Grid, IconButton, Paper, Tab, Tabs, useTheme } from "@material-ui/core"; +import { AccordionSummary, Box, Button, CardHeader, Container, Fab, Grid, IconButton, Paper, Tab, Tabs, useTheme } from "@material-ui/core"; import { DirectionsBoat, Edit } from "@material-ui/icons"; import React, { useEffect, useState } from "react"; import { useGlobalAppBar } from "../../components/navigation/GlobalAppBar/GlobalAppBar"; @@ -27,29 +27,29 @@ export function IOCDetailsView({ match }) { }, [ioc]); return ( - <Container> - <Paper> - <Grid container spacing={1}> - <Grid item xs={12}> - <Grid container justify="center"> - <Tabs - value={selectedTab} - onChange={handleTabChange} - indicatorColor="primary" - textColor="primary" - > - {ioc && ioc.activeDeployment && <Tab label="Live Status" value="Live Status" />} - {ioc && <Tab label="Configuration" value="Configuration" />} - </Tabs> + <Container> + <Paper> + <Grid container spacing={1}> + <Grid item xs={12}> + <Grid container justify="center"> + <Tabs + value={selectedTab} + onChange={handleTabChange} + indicatorColor="primary" + textColor="primary" + > + {ioc && ioc.activeDeployment && <Tab label="Live Status" value="Live Status" />} + {ioc && <Tab label="Configuration" value="Configuration" />} + </Tabs> + </Grid> + </Grid> + <Grid item xs={12}> + {selectedTab === "Live Status" && <IOCLiveStatus ioc={ioc} />} + {selectedTab === "Configuration" && <IOCConfiguration ioc={ioc} />} </Grid> </Grid> - <Grid item xs={12}> - {selectedTab === "Live Status" && <IOCLiveStatus ioc={ioc} />} - {selectedTab === "Configuration" && <IOCConfiguration ioc={ioc} />} - </Grid> - </Grid> - </Paper> - </Container> + </Paper> + </Container> );