Advertisement
Guest User

Untitled

a guest
Sep 11th, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { Component } from "react";
  2.  
  3. import Classes from "./Nightwing.css";
  4. import GlobalStyles from "../../global-css/styles";
  5.  
  6. // utilities
  7. import ActionEngine from "./utilities/ActionEngine";
  8. import Sorting from "./utilities/sorting";
  9.  
  10. import MATCH_TERMS_RAW from "./admin/job-type-match-terms.json";
  11.  
  12. /* COMPONENTS */
  13.  
  14. import GridRow from "../../hoc/GridRow";
  15. import FilterBar from "./components/FilterBar/FilterBar";
  16. import Table from "./components/Table/Table";
  17. import InfoBar from "./components/InfoBar/InfoBar";
  18. import LoadingBar from "./components/LoadingBar/LoadingBar";
  19. import ContextMenu from "./components/Table/ContextMenu/ContextMenu";
  20. import DuplicateWindow from "./components/Table/ContextMenu/DuplicateWindow/DuplicateWindow";
  21.  
  22. // sometimes the import comes back as a string, and sometimes as a parsed objected, either way this results in a parsed object
  23. const MATCH_TERMS = typeof MATCH_TERMS_RAW === "string" ? JSON.parse(MATCH_TERMS_RAW) : MATCH_TERMS_RAW;
  24.  
  25. class Nightwing extends Component {
  26.   state = {
  27.     jobList: [],
  28.     jobMap: {},
  29.     filteredJobList: [],
  30.     jobSelection: [],
  31.     sortProperty: "timeScheduled",
  32.     sortDirection: "desc",
  33.     tableOffset: 0,
  34.     tableCellDoubleClicked: null, // { rowNumber: Number, columnName: JobPropertyName }
  35.     contentIDListOpen: false,
  36.     contentIDListValue: "",
  37.     isLoading: false,
  38.     loadingPercent: null,
  39.     scrollBar: {
  40.       draggingScrollHead: false,
  41.       tableOffsetAtStart: null,
  42.       startPoint: null
  43.     },
  44.     contextMenu: {
  45.       visible: false,
  46.       position: {
  47.         left: null,
  48.         top: null
  49.       },
  50.       duplicatedJobDetails: []
  51.     },
  52.     filters: {
  53.       jobTypes: {
  54.         "submissions": true,
  55.         "transcodes": true,
  56.         "deliveries": true
  57.       },
  58.       jobStatuses: {
  59.         "cancelled": true,
  60.         "completed": true,
  61.         "failed": true,
  62.         "hold": true,
  63.         "pending": true,
  64.         "running": true
  65.       },
  66.       timeFrom: 0,
  67.       timeTo: 24 * 7
  68.     }
  69.   };
  70.  
  71.   /* CONSTANTS */
  72.  
  73.   // pixel values
  74.   TOP_AND_BOTTOM_BAR_HEIGHT = 60;
  75.   TABLE_ROW_HEIGHT = 24;
  76.  
  77.   // terms for filtering jobs
  78.   SUBMISSION_WORKFLOW_MATCH_TERMS = MATCH_TERMS.submission;
  79.   TRANSCODE_WORKFLOW_MATCH_TERMS = MATCH_TERMS.transcode;
  80.   DELIVERY_WORKFLOW_MATCH_TERMS = MATCH_TERMS.delivery;
  81.  
  82.   // handles talking to Action Engine for things like getting job data and manipulating jobs
  83.   AE = new ActionEngine();
  84.  
  85.   SORT_HIERARCHIES = {
  86.     "timeScheduled":  ["timeScheduled", "timeModified", "workflowID"],
  87.     "timeModified":   ["timeModified", "timeScheduled", "workflowID"],
  88.     "displayName":    ["displayName", "timeScheduled"],
  89.     "workflowID":     ["workflowID", "timeScheduled"],
  90.     "log":            ["log", "timeScheduled"],
  91.     "contentIDs":     ["contentIDs", "timeScheduled"],
  92.     "statusID":       ["statusID", "timeScheduled"],
  93.     "jobID":          [],
  94.     "priority":       ["priority", "timeScheduled"]
  95.   }
  96.  
  97.  
  98.  
  99.   /* EVENT HANDLERS */
  100.  
  101.   filterUpdateHandler = (filterType, filterName, boolValue) => {
  102.     const newFilters = {...this.state.filters};
  103.     newFilters[filterType][filterName] = boolValue;
  104.  
  105.     this.setState({filters: newFilters});
  106.   }
  107.  
  108.   timeFilterUpdateHandler = (whichTime, newTime) => {
  109.     const timeAsNumber = Number(newTime);
  110.     const newFilters = {...this.state.filters};
  111.     newFilters["time" + whichTime] = timeAsNumber;
  112.  
  113.     this.setState({filters: newFilters});
  114.   }
  115.  
  116.   tableOffsetUpdate = (scrollDeltaY) => {
  117.     const proposedNewTableOffset = this.state.tableOffset + (scrollDeltaY > 0 ? 1 : -1);
  118.     const newTableOffset = this.validateOffsetAmount(proposedNewTableOffset);
  119.    
  120.     this.setState({tableOffset: newTableOffset});
  121.   }
  122.  
  123.   scrollDragStartHandler = (clientY) => {
  124.     this.setState({
  125.       scrollBar: {
  126.         startPoint: clientY,
  127.         draggingScrollHead: true,
  128.         tableOffsetAtStart: this.state.tableOffset
  129.       }
  130.     })
  131.   }
  132.  
  133.   scrollDragEndHandler = () => {
  134.     this.setState({
  135.       scrollBar: {
  136.         anchorPoint: null,
  137.         draggingScrollHead: false,
  138.         tableOffsetAtStart: null
  139.       }
  140.     });
  141.   }
  142.  
  143.   scrollDragMoveHandler = (clientY) => {
  144.     if (this.state.scrollBar.draggingScrollHead) {
  145.       const distanceFromStartInPixels = clientY - this.state.scrollBar.startPoint;
  146.       const adjustedDistanceFromStart = distanceFromStartInPixels * (1 - this.determineScrollHeadHeightInPercent());
  147.       const numOfRowsPerPixel = this.determineNumOfRowsPerPixel();
  148.       const proposedNewTableOffset = this.state.scrollBar.tableOffsetAtStart + Math.round(adjustedDistanceFromStart * numOfRowsPerPixel);
  149.       const newTableOffset = this.validateOffsetAmount(proposedNewTableOffset);
  150.      
  151.       this.setState({
  152.         tableOffset: newTableOffset
  153.       })
  154.     }
  155.   }
  156.  
  157.   contentIDListVisiblityUpdate = (stateOfVisibility) => {
  158.     this.setState({contentIDListOpen: stateOfVisibility});
  159.   }
  160.  
  161.   contentIDListValueUpdate = (newValue) => {
  162.     this.setState({contentIDListValue: newValue});
  163.   }
  164.  
  165.   updateSortHandler = (propertyNameToSortBy) => {
  166.     const currentSortPropertyName = this.state.sortProperty;
  167.     const currentSortDirection = this.state.sortDirection;
  168.  
  169.     if (currentSortPropertyName === propertyNameToSortBy) {
  170.       const newSortDirection = currentSortDirection === "desc" ? "asc" : "desc";
  171.       this.setState({
  172.         sortProperty: currentSortPropertyName,
  173.         sortDirection: newSortDirection,
  174.         filteredJobList: [...this.state.filteredJobList].reverse()
  175.       });
  176.     } else {
  177.       this.setState({
  178.         sortProperty: propertyNameToSortBy,
  179.         sortDirection: "desc",
  180.         filteredJobList: Sorting.defaultSort([...this.state.filteredJobList], this.SORT_HIERARCHIES[propertyNameToSortBy], "desc")
  181.       });
  182.     }
  183.   }
  184.  
  185.   filteredListUpdateHandler = () => {
  186.     // validate time values
  187.     if (this.state.filters.timeFrom >= this.state.filters.timeTo) {
  188.       window.alert(`The "from" time cannot be equal to or greater than the "to" time.`);
  189.       return;
  190.     }
  191.  
  192.     const filters = this.state.filters;
  193.  
  194.     const checkForMatch = (workflowName, termToMatch) => {
  195.       return workflowName.toLowerCase().includes(termToMatch);
  196.     }
  197.  
  198.     const typeNameToFileNameMap = {"deliveries": "DELIVERY", "transcodes": "TRANSCODE", "submissions": "SUBMISSION" };
  199.     const jobTypeOrder = ["deliveries", "transcodes", "submissions"]; // this order is optimized for which workflows are most likely
  200.    
  201.     // create arrays for filtering the jobs
  202.     const activeJobStatuses = Object.keys(filters.jobStatuses).filter((statusName) => filters.jobStatuses[statusName]);
  203.     const contentIDListValues = this.state.contentIDListValue.split("\n").filter((value) => value.trim()).map((str) => Number(str));
  204.     const activeJobTypes = Object.keys(filters.jobTypes).filter((typeName) => filters.jobTypes[typeName]);
  205.     const activeJobTypesInOrder = jobTypeOrder.filter((typeName) => activeJobTypes.includes(typeName));
  206.  
  207.     if (activeJobStatuses.length === 0) {
  208.       window.alert("You haven't selected any job status filters.");
  209.       return;
  210.     } else if (activeJobTypesInOrder.length === 0) {
  211.       window.alert("You haven't selected any job type filters.");
  212.       return;
  213.     }
  214.  
  215.  
  216.     const filteredList = this.state.jobList.filter((job) => {
  217.       // filter out jobs that are too old
  218.       const maximumTime = Date.now() - (filters.timeFrom * 60 * 60 * 1000);
  219.       const minimumTime = Date.now() - (filters.timeTo * 60 * 60 * 1000);
  220.       if (job.timeScheduled > maximumTime) return false;
  221.       if (job.timeScheduled < minimumTime) return false;
  222.  
  223.       // filter out jobs that fail the job status filter
  224.       const passesJobStatusFilter = activeJobStatuses.find((statusName) => job.statusID === statusName);
  225.       if (!passesJobStatusFilter) return false;
  226.  
  227.       // filter out jobs that don't match a content ID from the filter list
  228.       const hasMatchingContentID = contentIDListValues.length === 0 || !!job.contentIDs.find((jobContentID) => {
  229.         return contentIDListValues.find((listID) => {
  230.           return jobContentID === listID;
  231.         });
  232.       });
  233.       if (!hasMatchingContentID) return false;
  234.  
  235.       // filter out jobs that don't match one of the job type filters
  236.       const workflowName = job.workflowID;
  237.       const passesJobTypeFilter = activeJobTypesInOrder.find((typeName) => {
  238.         const matchTerms = this[typeNameToFileNameMap[typeName] + "_WORKFLOW_MATCH_TERMS"];
  239.         const foundBlacklistMatch = !!matchTerms.blacklist.find((term) => checkForMatch(workflowName, term));
  240.         const foundWhitelistMatch = !!matchTerms.whitelist.find((term) => checkForMatch(workflowName, term));
  241.        
  242.         if (!foundBlacklistMatch && foundWhitelistMatch) return true;
  243.         else return false;
  244.       });
  245.       if (!passesJobTypeFilter) return false;
  246.  
  247.       // if all the checks are passed, this job passes the filter
  248.       return true;
  249.     });
  250.  
  251.     this.setState({
  252.       filteredJobList: filteredList,
  253.       jobSelection: [],
  254.       tableOffset: 0,
  255.       tableCellDoubleClicked: null
  256.     });
  257.   }
  258.  
  259.   tableRowClickToSelectHandler = (event, selectedJobIndex) => {
  260.     const { shiftKey, ctrlKey } = event;
  261.  
  262.     if (this.state.jobSelection.length === 0) {
  263.       this.setState({jobSelection: [selectedJobIndex]});
  264.     } else {
  265.       if (!ctrlKey && !shiftKey) {
  266.         this.setState({jobSelection: [selectedJobIndex]});
  267.       } else if (ctrlKey && !shiftKey) {
  268.         const newJobSelection = [...this.state.jobSelection];
  269.         const jobIndex = newJobSelection.indexOf(selectedJobIndex);
  270.         jobIndex === -1 ? newJobSelection.push(selectedJobIndex) : newJobSelection.splice(jobIndex, 1);
  271.         this.setState({jobSelection: newJobSelection});
  272.       } else if (shiftKey && !ctrlKey) {
  273.         if (this.state.jobSelection.length) {
  274.           const mostRecentSelectionJobIndex = this.state.jobSelection[this.state.jobSelection.length - 1];
  275.  
  276.           if (mostRecentSelectionJobIndex === selectedJobIndex) return;
  277.  
  278.           const newJobSelection = [...this.state.jobSelection];
  279.  
  280.           let i = mostRecentSelectionJobIndex > selectedJobIndex ? selectedJobIndex : mostRecentSelectionJobIndex + 1;
  281.           let end = mostRecentSelectionJobIndex > selectedJobIndex ? mostRecentSelectionJobIndex : selectedJobIndex + 1;
  282.           while (i !== end) {
  283.             if (!this.state.jobSelection.includes(i)) {
  284.               newJobSelection.push(i);
  285.              }
  286.  
  287.              i++;
  288.           }
  289.  
  290.           this.setState({jobSelection: newJobSelection});
  291.         }
  292.       }
  293.     }
  294.   }
  295.  
  296.   tableSelectAllHandler = () => {
  297.     const newJobSelection = [];
  298.     let i = 0;
  299.     while (i < this.state.filteredJobList.length) {
  300.       newJobSelection.push(i);
  301.       i++;
  302.     }
  303.     this.setState({jobSelection: newJobSelection});
  304.     setTimeout(() => window.getSelection().empty(), 0);
  305.   }
  306.  
  307.   tableCellDoubleClickToSelectHandler = (rowNumber, columnName) => {
  308.     this.setState({tableCellDoubleClicked: {
  309.       rowNumber, columnName
  310.     }});
  311.   }
  312.  
  313.   tableCellDoubleClickToSelectRemoveHandler = () => {
  314.     this.setState({tableCellDoubleClicked: null});
  315.   }
  316.  
  317.   tableRightClickDisplayContextMenu = (event, clickedJobIndex) => {
  318.     event.preventDefault();
  319.  
  320.     const currentContextMenuState = {...this.state.contextMenu};
  321.  
  322.     const updatedContextMenuState = {
  323.       ...currentContextMenuState,
  324.       visible: true,
  325.       position: {
  326.         left: event.clientX,
  327.         top: event.clientY,
  328.       }
  329.     };
  330.  
  331.     if (this.state.jobSelection.includes(clickedJobIndex)) {
  332.       this.setState({
  333.         contextMenu: updatedContextMenuState
  334.       });
  335.     } else {
  336.       this.setState({
  337.         contextMenu: updatedContextMenuState,
  338.         jobSelection: [clickedJobIndex]
  339.       });
  340.     }
  341.   }
  342.  
  343.   hideContextMenu = () => {
  344.     const currentContextMenuState = {...this.state.contextMenu};
  345.     this.setState({
  346.       contextMenu: {
  347.         ...currentContextMenuState,
  348.         visible: false,
  349.         position: {
  350.           left: null,
  351.           top: null,
  352.         }
  353.       }
  354.     })
  355.   }
  356.  
  357.   fetchJobXMLStringsHandler = () => {
  358.     const xmlFetchPromises = this.state.jobSelection.map((jobIndex) => {
  359.       return this.AE.getJobXmlString(this.state.filteredJobList[jobIndex].jobID);
  360.     });
  361.  
  362.     Promise.all(xmlFetchPromises)
  363.     .then((xmlStrings) => {
  364.       const duplicatedJobDetails = this.state.jobSelection.map((jobIndex, i) => {
  365.         return {
  366.           jobID: this.state.filteredJobList[jobIndex].jobID,
  367.           title: this.state.filteredJobList[jobIndex].displayName,
  368.           xmlString: xmlStrings[i]
  369.         };
  370.       });
  371.  
  372.       this.setState({
  373.         contextMenu: {
  374.           visible: false,
  375.           position: {
  376.             left: null,
  377.             top: null
  378.           },
  379.           duplicatedJobDetails: duplicatedJobDetails
  380.         }
  381.       });
  382.     });
  383.   }
  384.  
  385.   removeJobFromDuplicatedJobArray = (jobID) => {
  386.     const updatedDuplicatedJobDetails = [...this.state.contextMenu.duplicatedJobDetails];
  387.     const jobIndexInDuplicatedArray = updatedDuplicatedJobDetails.findIndex((jobDetails) => jobDetails.jobID === jobID);
  388.     updatedDuplicatedJobDetails.splice(jobIndexInDuplicatedArray, 1);
  389.  
  390.     const newContextMenuState = {
  391.       ...this.state.contextMenu,
  392.       duplicatedJobDetails: updatedDuplicatedJobDetails
  393.     };
  394.  
  395.     this.setState({
  396.       contextMenu: newContextMenuState
  397.     })
  398.   }
  399.  
  400.   submitDuplicatedJob = (xmlString, jobID) => {
  401.     this.AE.duplicateJob(xmlString, jobID)
  402.     .then(() => {
  403.       this.removeJobFromDuplicatedJobArray(jobID)
  404.     })
  405.     .catch((error) => {
  406.       window.alert(error);
  407.     });
  408.   }
  409.  
  410.   restartHandler = () => this.state.jobSelection.map((jobIndex) => this.AE.restartJob(this.state.filteredJobList[jobIndex].jobID));
  411.   cancelHandler = () => this.state.jobSelection.map((jobIndex) => this.AE.cancelJob(this.state.filteredJobList[jobIndex].jobID));
  412.   bumpHandler = () => this.state.jobSelection.map((jobIndex) => this.AE.bumpJob(this.state.filteredJobList[jobIndex].jobID));
  413.   continueHandler = () => this.state.jobSelection.map((jobIndex) => this.AE.continueJob(this.state.filteredJobList[jobIndex].jobID));
  414.  
  415.   jobActionHandler = (handlerFunction, actionName) => {
  416.     const actionPromises = handlerFunction();
  417.  
  418.     Promise.all(actionPromises)
  419.     .then(() => {
  420.       this.hideContextMenu();
  421.     })
  422.     .catch((error) => {
  423.       window.alert(`One or more jobs failed to ${actionName}.  Error:\n\n${error}`);
  424.     });
  425.   }
  426.  
  427.  
  428.  
  429.   /* UTLILITY METHODS */
  430.  
  431.   countJobsByStatus = (listStatePropertyName) => {
  432.     const countMap = {};
  433.     const jobStatusNames = Object.keys(this.state.filters.jobStatuses);
  434.     jobStatusNames.forEach((statusName) => countMap[statusName] = 0);
  435.  
  436.     this.state[listStatePropertyName].forEach((job) => countMap[job.statusID]++);
  437.  
  438.     return countMap;
  439.   }
  440.  
  441.   determineNumOfRowsThatFitInTable() {
  442.     const tableBodyHeightinPixels = window.innerHeight - ((this.TOP_AND_BOTTOM_BAR_HEIGHT * 2) + this.TABLE_ROW_HEIGHT);
  443.     const numOfJobsToDraw = Math.ceil(tableBodyHeightinPixels / this.TABLE_ROW_HEIGHT);
  444.     return numOfJobsToDraw;
  445.   }
  446.  
  447.   determineNumOfRowsPerPixel = () => {
  448.     return this.state.filteredJobList.length / this.determineMaxScrollBarHeadOffset();
  449.   }
  450.  
  451.   determineTableHeightInPixels = () => {
  452.     return (window.innerHeight - (this.TOP_AND_BOTTOM_BAR_HEIGHT * 2));
  453.   }
  454.  
  455.   determineScrollBarTrackHeightInPixels = () => {
  456.      return this.determineTableHeightInPixels() - this.TABLE_ROW_HEIGHT;
  457.   }
  458.  
  459.   determineScrollHeadHeightInPercent = () => {
  460.     const visibleJobsPercentOfTotal = this.determineNumOfRowsThatFitInTable() / this.state.filteredJobList.length;
  461.     return visibleJobsPercentOfTotal > 0.05 ? visibleJobsPercentOfTotal : 0.05;
  462.   }
  463.  
  464.   determineMaxTableOffset = () => {
  465.     return Math.max((this.state.filteredJobList.length - this.determineNumOfRowsThatFitInTable() + 1), 0);
  466.   }
  467.  
  468.   determineMaxScrollBarHeadOffset = () => {
  469.     return this.determineScrollBarTrackHeightInPixels() * (1 - this.determineScrollHeadHeightInPercent());
  470.   }
  471.  
  472.   validateOffsetAmount = (proposedValue) => {
  473.     const maxOffset = this.determineMaxTableOffset();
  474.  
  475.     proposedValue = proposedValue < 0 ? 0 : proposedValue;
  476.     proposedValue = proposedValue <= maxOffset ? proposedValue : maxOffset;
  477.  
  478.     return proposedValue;
  479.   }
  480.  
  481.  
  482.  
  483.   /* LIFECYCLE METHODS */
  484.  
  485.   componentDidMount() {
  486.     // after initial mount, reach out to Action Engine to grab all current jobs
  487.  
  488.     const loadingCallback = (percent) => {
  489.       this.setState({loadingPercent: percent});
  490.     };
  491.    
  492.     this.AE.getAllJobs(loadingCallback)
  493.     .then((jobs) => {
  494.       // create the initial job map
  495.       const jobMap = {};
  496.       jobs.forEach((job) => jobMap[job.jobID] = job);
  497.      
  498.       this.setState({
  499.         jobList: Sorting.defaultSort(jobs, this.SORT_HIERARCHIES[this.state.sortProperty], this.state.sortDirection),
  500.         jobMap: jobMap,
  501.         isLoading: false,
  502.         loadingPercent: null
  503.       });
  504.     });
  505.  
  506.     this.setState({isLoading: true, loadingPercent: 0});
  507.  
  508.     // set up global listener for ending scroll head drags
  509.     window.addEventListener("mouseup", () => this.scrollDragEndHandler());
  510.  
  511.     /* KEYBOARD SHORTCUTS */
  512.  
  513.     // Ctrl + A to select all job rows
  514.     window.addEventListener("keydown", (event) => {
  515.       const textInputIsNotActiveElement = !["input", "textarea"].includes(document.activeElement.tagName.toLowerCase());
  516.       if (event.ctrlKey && event.key.toLowerCase() === "a" && textInputIsNotActiveElement) {
  517.         this.tableSelectAllHandler();
  518.       }
  519.     });
  520.  
  521.     // PageUp/PageDown to scroll table by one "page"
  522.     window.addEventListener("keydown", (event) => {
  523.       const textInputIsNotActiveElement = !["input", "textarea"].includes(document.activeElement.tagName.toLowerCase());
  524.       if (["pagedown", "pageup"].includes(event.key.toLowerCase()) && textInputIsNotActiveElement) {
  525.         const direction = event.key.toLowerCase().replace("page", "");
  526.         const tableOffsetChange = direction === "up" ? -this.determineNumOfRowsThatFitInTable() : this.determineNumOfRowsThatFitInTable();
  527.         const currentTableOffset = this.state.tableOffset;
  528.         const proposedTableOffset = currentTableOffset + tableOffsetChange;
  529.         const newTableOffset = this.validateOffsetAmount(proposedTableOffset);
  530.         this.setState({
  531.           tableOffset: newTableOffset
  532.         });
  533.       }
  534.     });
  535.   }
  536.  
  537.   render() {
  538.     const globalAppStyles = {
  539.       color: GlobalStyles.FONT_COLOR,
  540.       gridTemplateRows: `${this.TOP_AND_BOTTOM_BAR_HEIGHT}px 1fr ${this.TOP_AND_BOTTOM_BAR_HEIGHT}px`
  541.     };
  542.  
  543.     const scrollBarTrackHeightInPixels = this.determineScrollBarTrackHeightInPixels();
  544.    
  545.     const scrollBarHeadHeightInPercent = Math.min(this.determineScrollHeadHeightInPercent(), 1);
  546.     const scrollBarHeadHeightInPixels = scrollBarHeadHeightInPercent * scrollBarTrackHeightInPixels;
  547.    
  548.     const numOfRowsThatFitInTable = this.determineNumOfRowsThatFitInTable();
  549.     const scrollDistanceInPercent = this.state.tableOffset === 0 ? 0 : this.state.tableOffset / (this.state.filteredJobList.length - numOfRowsThatFitInTable);
  550.     let scrollOffsetInPixels = scrollDistanceInPercent * this.determineMaxScrollBarHeadOffset();
  551.  
  552.  
  553.     // used in the top and bottom bars for positioning buttons and dropdowns
  554.     const TOP_BOTTOM_BAR_COLUMN_PADDING = 10;
  555.     const clickableElementStyles = {
  556.       width: `calc(100% - ${TOP_BOTTOM_BAR_COLUMN_PADDING * 2}px)`,
  557.       marginLeft: TOP_BOTTOM_BAR_COLUMN_PADDING + "px",
  558.       marginTop: TOP_BOTTOM_BAR_COLUMN_PADDING + "px",
  559.       height: this.TOP_AND_BOTTOM_BAR_HEIGHT - (TOP_BOTTOM_BAR_COLUMN_PADDING * 2) + "px"
  560.     };
  561.  
  562.     const contextMenu = this.state.contextMenu.visible ?
  563.       <ContextMenu
  564.         AE={this.AE}
  565.         position={this.state.contextMenu.position}
  566.         jobSelection={this.state.jobSelection.map((jobIndex) => this.state.filteredJobList[jobIndex])}
  567.         fetchJobXMLStringsHandler={this.fetchJobXMLStringsHandler}
  568.         jobActionHandler={this.jobActionHandler}
  569.         restartHandler={this.restartHandler}
  570.         cancelHandler={this.cancelHandler}
  571.         bumpHandler={this.bumpHandler}
  572.         continueHandler={this.continueHandler} />
  573.       : null
  574.  
  575.     const duplicateJobWindows = this.state.contextMenu.duplicatedJobDetails.map((jobDetails) => {
  576.       return (
  577.         <DuplicateWindow
  578.           xmlString={jobDetails.xmlString}
  579.           jobID={jobDetails.jobID}
  580.           title={jobDetails.title}
  581.           closeWindowHandler={this.removeJobFromDuplicatedJobArray}
  582.           submitHandler={this.submitDuplicatedJob} />
  583.       );
  584.     });
  585.  
  586.     return (
  587.       <div
  588.         className={Classes.Nightwing} style={globalAppStyles}
  589.         onMouseMove={(event) => this.scrollDragMoveHandler(event.clientY)}>
  590.         {contextMenu}
  591.         {duplicateJobWindows}
  592.         <GridRow row="1">
  593.           <FilterBar
  594.             clickableElementStyles={clickableElementStyles}
  595.             height={this.TOP_AND_BOTTOM_BAR_HEIGHT}
  596.             filters={this.state.filters}
  597.             contentIDListOpen={this.state.contentIDListOpen}
  598.             contentIDListVisiblityUpdate={this.contentIDListVisiblityUpdate}
  599.             contentIDListValue={this.state.contentIDListValue}
  600.             contentIDListValueUpdateHandler={this.contentIDListValueUpdate}
  601.             filterUpdateHandler={this.filterUpdateHandler}
  602.             timeFilterUpdateHandler={this.timeFilterUpdateHandler}
  603.             filteredListUpdateHandler={this.filteredListUpdateHandler} />
  604.         </GridRow>
  605.         <GridRow row="2">
  606.           <Table
  607.             jobsToDraw={this.state.filteredJobList.slice(this.state.tableOffset, this.state.tableOffset + numOfRowsThatFitInTable)}
  608.             tableOffset={this.state.tableOffset}
  609.             tableRowClickToSelectHandler={this.tableRowClickToSelectHandler}
  610.             tableCellDoubleClicked={this.state.tableCellDoubleClicked}
  611.             tableCellDoubleClickToSelectHandler={this.tableCellDoubleClickToSelectHandler}
  612.             tableCellDoubleClickToSelectRemoveHandler={this.tableCellDoubleClickToSelectRemoveHandler}
  613.             tableOffsetUpdateHandler={this.tableOffsetUpdate}
  614.             scrollDragStartHandler={this.scrollDragStartHandler}
  615.             scrollBarState={this.state.scrollBar}
  616.             rowHeight={this.TABLE_ROW_HEIGHT}
  617.             scrollBarTrackHeight={scrollBarTrackHeightInPixels}
  618.             scrollBarHeadHeight={scrollBarHeadHeightInPixels}
  619.             scrollOffset={scrollOffsetInPixels}
  620.             jobSelection={this.state.jobSelection}
  621.             contextMenu={this.state.contextMenu}
  622.             tableRightClickDisplayContextMenu={this.tableRightClickDisplayContextMenu}
  623.             tableClickHideContextMenu={this.hideContextMenu}
  624.             sortProperty={this.state.sortProperty}
  625.             sortDirection={this.state.sortDirection}
  626.             updateSortHandler={this.updateSortHandler}>
  627.             {this.state.isLoading ? <LoadingBar loadingPercent={this.state.loadingPercent} /> : null}
  628.           </Table>
  629.         </GridRow>
  630.         <GridRow row="3">
  631.           <InfoBar
  632.               clickableElementStyles={clickableElementStyles}
  633.               height={this.TOP_AND_BOTTOM_BAR_HEIGHT}
  634.               selectedCount={this.state.jobSelection.length}
  635.               resultCount={this.state.filteredJobList.length}
  636.               failureCount={this.countJobsByStatus("filteredJobList").failed || 0}
  637.               missingCount={23} />
  638.         </GridRow>
  639.       </div>
  640.     );
  641.   }
  642. }
  643.  
  644. export default Nightwing;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement