frontend/app/NewFrontPage.jsx (245 lines of code) (raw):

import React from 'react'; import axios from 'axios'; import DisplaySimpleText from './displayboxes/DisplaySimpleText.jsx'; import DisplayRecentUsers from "./displayboxes/DisplayRecentUsers.jsx"; import DisplayTextList from "./displayboxes/DisplayTextList.jsx"; import DisplayMdcPing from "./displayboxes/DisplayMdcPing.jsx"; import DisplayFibreDrivers from "./displayboxes/DisplayFibreDrivers.jsx"; import TimestampFormatter from "./common/TimestampFormatter.jsx"; import {validateRecord} from './validation.jsx'; import ValidateModel from "./validation/ValidateModel.jsx"; import ReactTooltip from "react-tooltip"; import ValidateIpAddresses from "./validation/ValidateIpAddresses.jsx"; import ValidateFCWWN from "./validation/ValidateFCWWN.jsx"; import ValidateLunCount from "./validation/ValidateLunCount.jsx"; import ValidateSanVolumes from "./validation/ValidateSanVolumes.jsx"; import ValidateFibreDrivers from "./validation/ValidateFibreDrivers.jsx"; import ValidateMdcPing from "./validation/ValidateMdcPing.jsx"; import ProblemsFilter from "./ProblemsFilter.jsx"; import SortSelector from "./SortSelector.jsx"; import moment from 'moment'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import ValidateDLC from "./validation/ValidateDLC.jsx"; import PropTypes from "prop-types"; import LoginButton from "./LoginButton.jsx"; class NewFrontPage extends React.Component { static propTypes = { currentUsername: PropTypes.string, isLoggedIn: PropTypes.bool.isRequired, loginErrorDetail: PropTypes.string, oAuthUri: PropTypes.string.isRequired, tokenUri: PropTypes.string.isRequired, clientId: PropTypes.string.isRequired, resource: PropTypes.string.isRequired, scope: PropTypes.string.isRequired, }; constructor(props){ super(props); this.state = { searchTerm: "", results: [], totalHitCount: null, loading: false, lastError: null, showRelativeTime: true, showDriverDetails: true, currentFilter: "all", filteredHitsCount: 0, sortField: "time", sortOrder: "descending", sortDone: false, data: [] }; this.updateSearchTerms = this.updateSearchTerms.bind(this); this.sortUpdated = this.sortUpdated.bind(this); const currentUri = new URL(window.location.href); this.redirectUri = currentUri.protocol + "//" + currentUri.host + "/oauth2/callback"; } componentWillMount(){ console.log(this.redirectUri); this.refresh(); } mapOutData(rawData){ const fcData = rawData.fibreChannel!==null ? { "fcWWN": rawData.fibreChannel.domains.map(dom=>dom.portWWN), "fcLunCount": rawData.fibreChannel.domains.map(dom=>dom.lunCount), "fcSpeed": rawData.fibreChannel.domains.map(dom=>dom.speed ? dom.speed : <span className="small-info">not connected</span>), "fcStatus": rawData.fibreChannel.domains.map(dom=>dom.status ? dom.status : <span className="small-info">not connected</span>), "fcAdaptor": rawData.fibreChannel.productName, "driverInfo": rawData.driverInfo ? rawData.driverInfo : null } : { "fcWWN": ["Not present"], "fcLunCount": ["Not present"], "fcSpeed": ["Not present"], "fcStatus": ["Not present"], "fcAdaptor": "Not present", "driverInfo": rawData.driverInfo ? rawData.driverInfo : null }; const initialMappedData = Object.assign({ "hostName": rawData.hostName, "computerName": rawData.computerName, "model": rawData.model, "hwUUID": rawData.hwUUID, "ipAddresses": rawData.ipAddresses, "lastUpdate": rawData.lastUpdate, "denyDlcVolumes": rawData.denyDlcVolumes, "mdcPing": rawData.mdcPing, "sanMounts": rawData.sanMounts, "plutoHelperAgentInfo": rawData.plutoHelperAgentInfo, "premiereProInfo": rawData.premiereProInfo }, fcData); return Object.assign({ validation: validateRecord(initialMappedData) }, initialMappedData); } componentDidUpdate(prevProps, prevState, snapshot) { console.log("componentDidUpdate from: ", prevState); console.log("componentDidUpdate to: ", this.state); if(prevState.currentFilter!==this.state.currentFilter || prevState.data!==this.state.data){ console.log("refiltering: ", this.state.currentFilter); const filteredHits = this.state.data.filter(entry=>this.state.currentFilter==="all" || this.state.currentFilter===entry.validation); console.log("filteredHits: ", filteredHits); this.setState({filteredHitsCount: filteredHits.length}); } } refresh(){ const searchTerm = encodeURIComponent(this.state.searchTerm ? this.state.searchTerm : "*"); this.setState({loading: true, lastError:null}, ()=>axios.get("/api/search/basic?q=" + searchTerm + "&length=100").then(result=>{ this.setState({data: result.data.entries.map(entry=>this.mapOutData(entry)), totalHitCount: result.data.entryCount, loading: false, lastError: null, sortDone: false}, ()=>this.doSort()); }).catch(err=>{ console.error(err); this.setState({loading: false, lastError: err, sortDone: true}); })); } shouldComponentUpdate(nextProps, nextState, nextContext) { if(!nextState.sortDone) return false; return true } doSort(){ const hostnameSortFunc = (a,b)=>{ const hostnameA = a.hostName; const hostnameB = b.hostName; return this.state.sortOrder==="ascending" ? hostnameA.localeCompare(hostnameB) : hostnameB.localeCompare(hostnameA); }; const updateTimeSortFunc = (a,b)=>{ const updatedA = moment(a.lastUpdate); const updatedB = moment(b.lastUpdate); if(updatedA.isSame(updatedB)) return 0; const reverse = this.state.sortOrder==="ascending" ? updatedB.isBefore(updatedA) : updatedA.isBefore(updatedB); return reverse ? -1 : 1; }; let currentSortFunc; if(this.state.sortField==="hostname") currentSortFunc = hostnameSortFunc; if(this.state.sortField==="time") currentSortFunc = updateTimeSortFunc; const sorted = this.state.data.sort(currentSortFunc); this.setState({data: sorted, sortDone: true}); } updateSearchTerms(evt){ this.setState({searchTerm: evt.target.value}, ()=>this.refresh()); } sortUpdated(newField, newOrder){ console.log("sortUpdated: ", newField, newOrder); this.setState({sortField: newField, sortOrder:newOrder},()=>this.doSort()); } deleteItem(event, item) { console.log('About to delete record for '+item); let axiosConfig = { headers: { "Content-Type": "application/json" } } const sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) } axios.delete("/api/delete/" + item, axiosConfig).then(response=> { this.setState({loading:true}, ()=>sleep(1000).then(()=>this.refresh())); } ) } render() { if (this.props.isLoggedIn) { return ( <div> <h1>Fibre Census</h1> <div className="centered"> <label htmlFor="search-box">Search:</label> <input type="text" id="search-box" style={{width: "50%"}} onChange={this.updateSearchTerms}/> <img style={{marginLeft:"auto",marginRight:"auto",width:"44px", display: this.state.loading ? "inline" : "none" }} src="/assets/images/Spinner-1s-44px.svg"/> <input type="checkbox" checked={this.state.showDriverDetails} id="driver-details-check" onChange={event=>this.setState({showDriverDetails: !this.state.showDriverDetails})}/> <label htmlFor="driver-details-check">Show driver details</label><br/> <label>Showing</label><ProblemsFilter onChange={evt=>this.setState({currentFilter: evt.target.value})} value={this.state.currentFilter}/> <span className="informative">{ this.state.filteredHitsCount===this.state.data.length ? "Showing " + this.state.data.length + " reports" : "Showing " + this.state.filteredHitsCount + " from a total of " + this.state.data.length + " reports" }</span><br/> <label>Sorted by</label><SortSelector value={this.state.sortField} order={this.state.sortOrder} onChange={this.sortUpdated}/> </div> <ul className="boxlist"> { this.state.data.map(entry=><li key={entry.hostName} className={"entry-container " + entry.validation} style={{display: this.state.currentFilter==="all" || this.state.currentFilter===entry.validation ? "block" : "none"}}> <span className="entry-header">{entry.hostName} - <span className="entry-header-additional"><TimestampFormatter relative={this.state.showRelativeTime} value={entry.lastUpdate}/></span><span className="float-right"><FontAwesomeIcon icon="times-circle" onClick={e => window.confirm("This entry will be deleted.\nContinue?") && this.deleteItem(e, entry.hostName)} /></span></span> <DisplayFibreDrivers title="Fibre drivers present" listData={entry.driverInfo} showDetails={this.state.showDriverDetails} validationComponent={<ValidateFibreDrivers listData={entry.driverInfo}/>} extraClasses="oversized float-right" /> <DisplaySimpleText title="Model" entry={entry.model} validationComponent={<ValidateModel stringData={entry.model}/>} extraClasses="model"/> <DisplaySimpleText title="Computer Name" entry={entry.computerName} extraClasses="even-wider"/> <DisplayTextList title="IP Addresses" bulletIcon="network-wired" listData={entry.ipAddresses} validationComponent={<ValidateIpAddresses listData={entry.ipAddresses}/>} extraClasses="ip" /> <DisplayRecentUsers title="Recent Users" entry={entry} extraClasses="doublewidth"/> <DisplayTextList title="Fibre WWNs" listData={entry.fcWWN} extraClasses="fibre" validationComponent={<ValidateFCWWN listData={entry.fcWWN}/>}/> <DisplayTextList title="Fibre status" listData={entry.fcStatus}/> <DisplayTextList title="Fibre speed" listData={entry.fcSpeed}/> <DisplayTextList title="LUN count" listData={entry.fcLunCount} validationComponent={<ValidateLunCount listData={entry.fcLunCount}/>} extraClasses="lun"/> <DisplayTextList title="UseDLC" listData={entry.denyDlcVolumes} validationComponent={<ValidateDLC listData={entry.denyDlcVolumes}/>} extraClasses="dlc" /> <DisplaySimpleText title="Fibre adaptor model" entry={entry.fcAdaptor} extraClasses="wider"/> <DisplayMdcPing title="MDC Controller Connectivity" listData={entry.mdcPing} extraClasses="doublewidth" validationComponent={<ValidateMdcPing listData={entry.mdcPing}/>} /> <DisplayTextList title="SAN mounts" bulletIcon="hdd" listData={entry.sanMounts ? entry.sanMounts.map(m=>m.name) : null} validationComponent={<ValidateSanVolumes listData={entry.sanMounts ? entry.sanMounts.map(m=>m.name) : null}/>} /> <DisplaySimpleText title="Pluto Helper Agent Version" entry={entry.plutoHelperAgentInfo} extraClasses="doublewidth"/> <DisplaySimpleText title="Premiere Pro Version" entry={entry.premiereProInfo} extraClasses="doublewidth"/> </li> ) } </ul> <ReactTooltip/> </div> ); } else { return ( <div> {this.props.loginErrorDetail ? ( <p className="error">{this.props.loginErrorDetail}</p> ) : null} Click here to log in to Fibre Census:{" "} <LoginButton oAuthUri={this.props.oAuthUri} tokenUri={this.props.tokenUri} clientId={this.props.clientId} redirectUri={this.redirectUri} resource={this.props.resource} state={this.props.redirectingTo} scope={this.props.scope} /> </div> ); } } } export default NewFrontPage;