import React, { useState, useEffect } from "react"; /* * It works a little something like this: * Choose what source and destination action you want * Select the source field to be used for a required destination field OR * write a static value for the field (FIXME) OR * run a generator action for the field (FIXME, these should be e.g. run workflow and get result) */ import Grid from "@material-ui/core/Grid"; import Dialog from "@material-ui/core/Dialog"; import DialogTitle from "@material-ui/core/DialogTitle"; import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import ButtonBase from "@material-ui/core/ButtonBase"; import TextField from "@material-ui/core/TextField"; import MenuItem from "@material-ui/core/MenuItem"; import Paper from "@material-ui/core/Paper"; import Button from "@material-ui/core/Button"; import FormControl from "@material-ui/core/FormControl"; import Select from "@material-ui/core/Select"; import InputLabel from "@material-ui/core/InputLabel"; import Table from "@material-ui/core/Table"; import InputAdornment from "@material-ui/core/InputAdornment"; import TableBody from "@material-ui/core/TableBody"; import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; import SearchIcon from "@material-ui/icons/Search"; import DeleteIcon from "@material-ui/icons/Delete"; import Downshift from "downshift"; import deburr from "lodash/deburr"; const EditSchedule = (props) => { const { globalUrl } = props; const [tmpSrcApp, setTmpSrcApp] = useState({}); const [tmpDstApp, setTmpDstApp] = useState({}); const [srcApp, setSrcApp] = useState({}); const [srcAppConfig, setSrcAppConfig] = useState([]); const [srcAppConfigOpen, setSrcAppConfigOpen] = useState(false); const [srcAppAction, setSrcAppAction] = useState(""); const [dstApp, setDstApp] = useState({}); const [dstAppAction, setDstAppAction] = useState(""); const [dstAppConfig, setDstAppConfig] = useState([]); const [dstAppConfigOpen, setDstAppConfigOpen] = useState(false); // Lets set the real data here const [selectedSrc, setSelectedSrc] = React.useState(""); const [, setSelectedSrcData] = React.useState({}); const [selectedDst, setSelectedDst] = React.useState([]); // FIXME const [suggestions, setSuggestions] = React.useState([]); const [inputappdata, setInputAppData] = React.useState({}); const [scheduleConfig, setScheduleConfig] = React.useState({}); const [selectedSrcParameters, setSelectedSrcParameters] = React.useState([]); const getCurrentSchedule = () => { fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig(responseJson); }) .catch((error) => { console.log(error); }); }; const loadAppSuggestions = () => { fetch(globalUrl + "/api/v1/schedules/apps", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, }) .then((response) => response.json()) .then((responseJson) => { setSuggestions(responseJson.apps); }) .catch((error) => { console.log(error); }); }; // FIXME - this is generated from app selection input with required items useEffect(() => { if (Object.getOwnPropertyNames(scheduleConfig).length <= 0) { getCurrentSchedule(); } // Load apps if destination or source is if (suggestions.length === 0) { loadAppSuggestions(); } // Load everything else if ( Object.getOwnPropertyNames(scheduleConfig).length > 0 && Object.getOwnPropertyNames(scheduleConfig.appinfo.sourceapp).length > 0 && Object.getOwnPropertyNames(srcApp).length <= 0 ) { if (scheduleConfig.appinfo.sourceapp.name.length > 0) { setSrcApp(scheduleConfig.appinfo.sourceapp); setSrcAppAction(scheduleConfig.appinfo.sourceapp.action); } } // Use sourceapp.name&version and sourceapp.action and look for name in inputappdata // Basically fix everything in this one lol if ( suggestions.length > 0 && srcAppAction.length > 0 && Object.getOwnPropertyNames(scheduleConfig).length > 0 && Object.getOwnPropertyNames(inputappdata).length <= 0 ) { // Loops all apps and finds current for (var key in suggestions) { var curapp = suggestions[key]; if (curapp.name === srcApp.name) { break; } } setInputAppData(curapp); // Loops the apps actions to find current for (key in curapp.output) { var curappaction = curapp.output[key]; if (curappaction.name === srcAppAction) { break; } } setSelectedSrcParameters(curappaction.outputparameters); if (curappaction.config !== null && curappaction.config !== undefined) { setSrcAppConfig(curappaction.config); } // FIXME - set src of all translator nodes to curappaction.outputparameters[0] if not defined //value={scheduleConfig.translator[count].src.name} //console.log(scheduleConfig) var newtranslator = []; for (key in scheduleConfig.translator) { var curtranslator = scheduleConfig.translator[key]; // Overwrite issues if (curtranslator.src.name === "") { curtranslator.src = curappaction.outputparameters[0]; } newtranslator.push(curtranslator); } scheduleConfig.translator = newtranslator; setScheduleConfig(scheduleConfig); } if ( suggestions.length > 0 && dstAppAction.length <= 0 && Object.getOwnPropertyNames(scheduleConfig).length > 0 ) { // Loops all apps and finds current for (key in suggestions) { curapp = suggestions[key]; if (curapp.name === dstApp.name) { break; } } const curAction = scheduleConfig.appinfo.destinationapp.action; // Loops the apps actions to find current for (key in curapp.output) { curappaction = curapp.output[key]; if (curappaction.name === curAction) { break; } } setDstAppAction(curappaction.name); if (curappaction.config !== null && curappaction.config !== undefined) { setDstAppConfig(curappaction.config); } } }); const getSuggestions = (value, type, { showEmpty = false } = {}) => { const inputValue = deburr(value.trim()).toLowerCase(); const inputLength = inputValue.length; let count = 0; return inputLength === 0 && !showEmpty ? [] : suggestions.filter((suggestion) => { const keep = count < 5 && suggestion.types && suggestion.types.includes(type) && suggestion.name.slice(0, inputLength).toLowerCase() === inputValue; if (keep) { count += 1; } return keep; }); }; const setSrcAppWrapper = (currentapps) => { setSrcApp(currentapps[0]); if (currentapps[0].output.length > 0) { selectSrcAction(currentapps[0].output[0].name); } }; const setDstAppWrapper = (currentapps) => { setDstApp(currentapps[0]); if (currentapps[0].input.length > 0) { selectInitialDstAction(currentapps); } }; const renderInput = (type, inputProps) => { const { InputProps, classes, ref, ...other } = inputProps; // Sets the srcapp if string is matching exactly for name if ( InputProps["aria-activedescendant"] === null && InputProps["value"].length > 0 ) { const currentapps = suggestions.filter( (data) => data.name === InputProps["value"] ); if (currentapps.length === 1) { if (type === "output") { if (currentapps[0].name !== srcApp.name) { setSrcAppWrapper(currentapps); } } else if (type === "input") { if (currentapps[0].name !== dstApp.name) { setDstAppWrapper(currentapps); } } } } return (
), }} {...other} />
); }; const renderSuggestion = (suggestionProps) => { const { suggestion, index, itemProps, highlightedIndex, selectedItem } = suggestionProps; const isHighlighted = highlightedIndex === index; const isSelected = (selectedItem || "").indexOf(suggestion.name) > -1; return ( {suggestion.name} ); }; const bodyDivStyle = { marginLeft: "20px", marginTop: "50px", marginRight: "20px", margin: "auto", width: "1350px", display: "flex", }; const appActionStyle = { height: "50px", marginTop: "10px", }; // FIXME - set this //const setRelationshipsFromSource = () => { //} //// FIXME - set this //const setRelationshipsFromGenerator = () => { //} const selectDstAppAction = (event) => { if (event.target.value === dstAppAction) { return; } setDstAppAction(event.target.value); refactorTranslations(event.target.value); }; const refactorTranslations = (action) => { // dstapp is chosen var found = false; for (var key in dstApp.input) { var curinput = dstApp.input[key]; if (curinput.name === action) { found = true; break; } } // Should never happen.. if (!found) { return; } var tmprelationships = []; for (key in curinput.inputparameters) { var curRelation = { dst: curinput.inputparameters[key], src: {} }; tmprelationships.push(curRelation); } scheduleConfig["translator"] = tmprelationships; setScheduleConfig(scheduleConfig); }; const selectInitialDstAction = (value) => { var action = value[0].input[0].name; setDstAppAction(action); var found = false; for (var key in value) { var curinput = value[0].input[key]; if (curinput.name === action) { found = true; break; } } // Should never happen.. if (!found) { return; } var tmprelationships = []; for (key in curinput.inputparameters) { var curRelation = { dst: curinput.inputparameters[key], src: {} }; tmprelationships.push(curRelation); } scheduleConfig["translator"] = tmprelationships; setScheduleConfig(scheduleConfig); }; const selectSrcAction = (value) => { // FIXME - load the config for this action var found = false; setSrcAppAction(value); var curitem = {}; for (var key in inputappdata.output) { curitem = inputappdata.output[key]; if (curitem.name === value) { found = true; break; } } if (!found) { setSelectedSrcParameters([]); return; } // Generate this for every relation? setSelectedSrcParameters(curitem.outputparameters); //FIXME - check if source has the right attribute var tmprelationships = []; key = 0; for (key in scheduleConfig.translator) { var curRelation = scheduleConfig.translator[key]; curRelation["src"] = curitem.outputparameters[0]; tmprelationships.push(curRelation); } scheduleConfig["translator"] = tmprelationships; setScheduleConfig(scheduleConfig); }; // Wrapper to handle event click const selectSrcActionWrapper = (event) => { return selectSrcAction(event.target.value); }; const srcappaction = Object.getOwnPropertyNames(srcApp).length > 0 && srcApp.output ? (
Actions
) : null; const dstappaction = Object.getOwnPropertyNames(dstApp).length > 0 ? (
Actions
) : null; const downshiftStyle = { //marginLeft: "20px", //marginTop: "20px", //marginRight: "20px", display: "flex", width: "100%", }; const submitDisabled = selectedSrc.length > 0 && selectedDst.length > 0; const submitButtonClick = () => { var newtranslations = []; var tobeadded = []; var tobechanged = []; // Go find the information again in testdata //newrelationship["translator"] = {"src": {}, "dst": {}} //newrelationship["static"] = {} // Reformat relationships // clean up old relationships // if (Object.getOwnPropertyNames(scheduleConfig.Translator).length <= 0) { return; } // Clean up old translations for specified elements // FIXME - maybe just send a request with relationships and fix in backend? // FIXME - there is an issue here for some multifield stuff // Literally have to verify every single one anyway.. for (var selected in selectedDst) { var found = false; var index = 0; for (var key in scheduleConfig["translator"]) { if ( scheduleConfig["translator"][key]["dst"]["name"] === selectedDst[selected] ) { index = key; found = true; break; } } if (!found) { tobeadded.push(selectedDst[selected]); } else { // Dst can be the tobechanged.push(index); } } var tmprelationships = scheduleConfig; key = 0; for (key in scheduleConfig["translator"]) { if (tobechanged.includes(key)) { var tmprel = scheduleConfig["translator"][key]; tmprel["src"] = { name: selectedSrc }; tmprelationships["translator"].splice(key, 1); newtranslations.push(tmprel); } } key = 0; for (key in tobeadded) { tmprel = { src: { name: selectedSrc }, dst: { name: tobeadded[key] } }; newtranslations.push(tmprel); } // delete deletable keys from copy (new) // key = 0; for (key in newtranslations) { tmprelationships["translator"].push(newtranslations[key]); } setSelectedSrc(""); setSelectedDst([]); setSelectedSrcData({}); // FIXME - does this work? scheduleConfig["translator"] = tmprelationships["translator"]; setScheduleConfig(scheduleConfig); }; // When it's set, need to find the destination in the row and set static const setStaticValue = (event, row) => { console.log("HI"); // FIXME - modify the row first // FIXME - set generator and source to "nothing" console.log(row.dst.name); console.log(row); console.log(event.target.value); var newsrcrow = { name: "static", description: "Static value set", type: "static", value: event.target.value, schema: { type: "string" }, }; var relationshipclone = JSON.parse(JSON.stringify(scheduleConfig)); for (var key in scheduleConfig["translator"]) { var curItem = scheduleConfig["translator"][key]; if (curItem.dst.name === row.dst.name) { break; } } relationshipclone["translator"][key]["src"] = newsrcrow; scheduleConfig["translator"] = relationshipclone["translator"]; console.log(scheduleConfig); // Fuck this :( // DO DIS IN FRONTEND AND HAVE A SUBMIT BUTTON :( fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(scheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); }) .catch((error) => { console.log(error); }); }; // Rewrites relationships clientside const setCurrentSrcPropRelation = (event, rowkey) => { console.log(event, rowkey); var found = false; for (var key in selectedSrcParameters) { var curItem = selectedSrcParameters[key]; if (curItem.name === event.target.value) { found = true; break; } } // No idea how this would ever happen, but but (: if (!found) { return; } var row = scheduleConfig.translator[rowkey]; var rowclone = JSON.parse(JSON.stringify(row)); rowclone.src = curItem; var relationshipclone = JSON.parse(JSON.stringify(scheduleConfig)); for (key in scheduleConfig["translator"]) { curItem = scheduleConfig["translator"][key]; if (curItem.dst.name === row.dst.name) { break; } } relationshipclone["translator"][key] = rowclone; scheduleConfig["translator"] = relationshipclone["translator"]; console.log(scheduleConfig); // Fuck this :( // DO DIS IN FRONTEND AND HAVE A SUBMIT BUTTON :( fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(scheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); }) .catch((error) => { console.log(error); }); return; }; const relationshipBody = Object.getOwnPropertyNames(scheduleConfig).length > 0 && scheduleConfig["translator"] !== undefined && scheduleConfig.translator.length > 0 ? ( Action Source Field Destination Field Field Type Required Static Generator Transform {scheduleConfig.translator.map((row, count) => { var buttonIcon = ; if (!row.dst.required) { buttonIcon = ( ); } const srcpropsSelector = (Object.getOwnPropertyNames(selectedSrcParameters).length > 0 || Object.getOwnPropertyNames(scheduleConfig.translator).length > 0) && Object.getOwnPropertyNames(srcApp).length > 0 ? ( ) : (
No defined fields
); const placeholderValue = row.src.type === "static" ? row.src.value : "... Set a static value"; return ( {buttonIcon} {srcpropsSelector} {row.dst.name} {row.dst.schema.type} {row.dst.required} { if (event.key === "Enter") { event.preventDefault(); console.log(`Pressed keyCode ${event.key}`); setStaticValue(event, row); } }} /> INSERT SCRIPT THINGY - Cortex responder? ); })}
) : null; // FIXME - use this //const submitRelationships = () => { // // Make an API-call to the backend for verification // // Return with failures etc, and mark row issues? // // var apiUrl = "http://localhost:5000" // fetch(apiUrl+"/api/v1/schedules", // { // method: "POST", // headers: {"content-type": "application/json"}, // body: JSON.stringify(scheduleConfig), // } // ) // .then((response) => response.json()) // .then((responseJson) => { // console.log(responseJson) // }) // .catch((error) => { // console.log(error); // }); //} const executeSchedule = () => { fetch( globalUrl + "/api/v1/schedules/" + props.match.params.key + "/execute", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, } ) .then((response) => response.json()) .then((responseJson) => { console.log(responseJson); }) .catch((error) => { console.log(error); }); }; const submitButton = (
); // Requires src or dst as input // FIXME - use this shit to edit an app or something //const editButtonFix = (app, apptype) => { // if (apptype === "src") { // } else if (apptype === "dst") { // } //} const editSrcApp = (event) => { // if tmpsrcapp, show RESET (can be an X or something too) // if reset is clicked, set source app back to the original setTmpSrcApp(scheduleConfig.appinfo.sourceapp); var tmpscheduleConfig = scheduleConfig; tmpscheduleConfig.appinfo.sourceapp = {}; fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(tmpscheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); setSrcApp({}); setSrcAppAction(""); }) .catch((error) => { console.log(error); }); }; const editDstApp = (event) => { // if tmpsrcapp, show RESET (can be an X or something too) // if reset is clicked, set source app back to the original setTmpDstApp(scheduleConfig.appinfo.destinationapp); var tmpscheduleConfig = scheduleConfig; tmpscheduleConfig.appinfo.destinationapp = {}; fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(tmpscheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); setDstApp({}); setDstAppAction(""); }) .catch((error) => { console.log(error); }); }; const scheduleApp = (app, actiondata) => { const editButton = actiondata === "src" ? ( ) : ( ); const configureButton = actiondata === "src" ? ( ) : ( ); // FIXME - set src vs dst return ( {splitter}

{app.name}

{app.description}
{app.action}
{splitter}
{editButton}
{configureButton}
); }; const splitter = (
); const dstDownshift = ( {({ getInputProps, getItemProps, getMenuProps, highlightedIndex, inputValue, isOpen, selectedItem, }) => (
{renderInput("input", { fullWidth: true, InputProps: getInputProps({ placeholder: "Search destination apps", }), })}
{isOpen ? ( {getSuggestions(inputValue, "input").map( (suggestion, index) => renderSuggestion({ suggestion, index, itemProps: getItemProps({ item: suggestion.name }), highlightedIndex, selectedItem, }) )} ) : null}
{dstappaction}
)}
); const srcDownshift = ( {({ getInputProps, getItemProps, getMenuProps, highlightedIndex, inputValue, isOpen, selectedItem, }) => (
{renderInput("output", { fullWidth: true, InputProps: getInputProps({ placeholder: "Search source apps", }), })}
{isOpen ? ( {getSuggestions(inputValue, "output").map( (suggestion, index) => renderSuggestion({ suggestion, index, itemProps: getItemProps({ item: suggestion.name }), highlightedIndex, selectedItem, }) )} ) : null}
{srcappaction}
)}
); const submitDstApp = (event) => { var packagedSrc = { name: dstApp.name, id: dstApp.id, description: dstApp.description, action: dstAppAction, }; var tmpscheduleConfig = scheduleConfig; tmpscheduleConfig.appinfo.destinationapp = packagedSrc; // Hmm, do this here? Idk fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(tmpscheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); }) .catch((error) => { console.log(error); }); }; const submitSrcApp = (event) => { var packagedSrc = { name: srcApp.name, id: srcApp.id, description: srcApp.description, action: srcAppAction, }; var tmpscheduleConfig = scheduleConfig; // FIXME - future fred // tmpscheduleConfig.appinfo.sourceapp = packagedSrc; // Hmm, do this here? Idk fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(tmpscheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); }) .catch((error) => { console.log(error); }); }; const resetDstApp = (event) => { var tmpscheduleConfig = scheduleConfig; tmpscheduleConfig.appinfo.destinationapp = tmpDstApp; // Hmm, do this here? Idk fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(tmpscheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); setDstApp(tmpSrcApp); setDstAppAction(tmpDstApp.action); setTmpDstApp({}); }) .catch((error) => { console.log(error); }); }; const resetSrcApp = (event) => { var tmpscheduleConfig = scheduleConfig; tmpscheduleConfig.appinfo.sourceapp = tmpSrcApp; // Hmm, do this here? Idk fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(tmpscheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { setScheduleConfig({}); setSrcApp(tmpSrcApp); setSrcAppAction(tmpSrcApp.action); setTmpSrcApp({}); }) .catch((error) => { console.log(error); }); }; // Based on some srcthing const searchGridSrc = ( Choose Source app (FIXME) - clickable {splitter}
{srcDownshift}
{splitter}
); const searchGridDst = ( Choose Source app (FIXME) - clickable {splitter}
{dstDownshift}
{splitter}
); const srcField = Object.getOwnPropertyNames(scheduleConfig).length > 0 && Object.getOwnPropertyNames(scheduleConfig.appinfo.sourceapp).length > 0 && scheduleConfig.appinfo.sourceapp.name.length > 0 ? (
{scheduleApp(scheduleConfig.appinfo.sourceapp, "src")}
) : (
{searchGridSrc}
); const dstField = Object.getOwnPropertyNames(scheduleConfig).length > 0 && Object.getOwnPropertyNames(scheduleConfig.appinfo.destinationapp).length > 0 && scheduleConfig.appinfo.destinationapp.name.length > 0 ? (
{scheduleApp(scheduleConfig.appinfo.destinationapp, "dst")}
) : (
{searchGridDst}
); // Have to use array cus of datastore lol (no map[string]string) const srcModalData = []; const buildSrcModal = (event, fieldname) => { var fieldfound = false; for (var key in srcModalData) { if (srcModalData[key]["key"] === fieldname) { fieldfound = true; srcModalData[key]["value"] = event.target.value; break; } } if (!fieldfound) { srcModalData.push({ key: fieldname, value: event.target.value }); } console.log(srcModalData); }; // FIXME - verify required fields? const submitSrcConfig = () => { scheduleConfig.appinfo.sourceapp.config = srcModalData; setScheduleConfig(scheduleConfig); setSrcAppConfigOpen(false); fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(scheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { console.log(responseJson); }) .catch((error) => { console.log(error); }); }; const dstModalData = []; const buildDstModal = (event, fieldname) => { var fieldfound = false; for (var key in dstModalData) { if (dstModalData[key]["key"] === fieldname) { fieldfound = true; dstModalData[key]["value"] = event.target.value; break; } } if (!fieldfound) { dstModalData.push({ key: fieldname, value: event.target.value }); } console.log(dstModalData); }; // FIXME - verify required fields const submitDstConfig = () => { scheduleConfig.appinfo.destinationapp.config = dstModalData; setScheduleConfig(scheduleConfig); setDstAppConfigOpen(false); fetch(globalUrl + "/api/v1/schedules/" + props.match.params.key, { method: "PUT", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(scheduleConfig), }) .then((response) => response.json()) .then((responseJson) => { console.log(responseJson); }) .catch((error) => { console.log(error); }); }; const dstConfigModal = dstAppConfigOpen ? ( { setDstAppConfigOpen(false); }} > Source configuration Configure {dstApp.name}'s required fields {dstAppConfig.map((data) => ( { buildDstModal(event, data.name); }} autofocus color="primary" name="searchtext" placeholder={data.name} margin="dense" id={data.name} label={data.name} fullWidth /> ))} ) : null; // FIXME - load the actual fields! const srcConfigModal = srcAppConfigOpen ? ( { setSrcAppConfigOpen(false); }} > Source configuration Configure {srcApp.name}'s required fields {srcAppConfig.map((data) => ( { buildSrcModal(event, data.name); }} autofocus color="primary" name="searchtext" placeholder={data.name} margin="dense" id={data.name} label={data.name} fullWidth /> ))} ) : null; return (
{srcConfigModal} {dstConfigModal}
{srcField} {dstField}
{submitButton}
{relationshipBody}
); }; export default EditSchedule;