diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py index ee1f4cd4..f2a7c3f1 100644 --- a/backend/app_sdk/app_base.py +++ b/backend/app_sdk/app_base.py @@ -36,6 +36,16 @@ class AppBase: self.start_time = int(time.time()) self.result_wrapper_count = 0 + self.action_result = { + "action": self.action, + "authorization": self.authorization, + "execution_id": self.current_execution_id, + "result": f"", + "started_at": self.start_time, + "status": "", + "completed_at": int(time.time()), + } + if isinstance(self.action, str): try: self.action = json.loads(self.action) @@ -489,7 +499,7 @@ class AppBase: #print(f"NEW PARAMS: {new_params}") if len(new_params) == 0: print("[WARNING] SHOULD STOP MULTI-EXECUTION BECAUSE FIELDS AREN'T UNIQUE") - action_result = { + self.action_result = { "action": self.action, "authorization": self.authorization, "execution_id": self.current_execution_id, @@ -499,7 +509,7 @@ class AppBase: "completed_at": int(time.time()), } - self.send_result(action_result, {"Content-Type": "application/json", "Authorization": "Bearer %s" % self.authorization}, "/api/v1/streams") + self.send_result(self.action_result, {"Content-Type": "application/json", "Authorization": "Bearer %s" % self.authorization}, "/api/v1/streams") exit() #return else: @@ -834,7 +844,7 @@ class AppBase: # !!! Let this line stay - its used for some horrible codegeneration / stitching !!! # #STARTCOPY stream_path = "/api/v1/streams" - action_result = { + self.action_result = { "action": action, "authorization": self.authorization, "execution_id": self.current_execution_id, @@ -861,20 +871,20 @@ class AppBase: if len(self.action) == 0: print("ACTION env not defined") - action_result["result"] = "Error in setup ENV: ACTION not defined" - self.send_result(action_result, headers, stream_path) + self.action_result["result"] = "Error in setup ENV: ACTION not defined" + self.send_result(self.action_result, headers, stream_path) return if len(self.authorization) == 0: print("AUTHORIZATION env not defined") - action_result["result"] = "Error in setup ENV: AUTHORIZATION not defined" - self.send_result(action_result, headers, stream_path) + self.action_result["result"] = "Error in setup ENV: AUTHORIZATION not defined" + self.send_result(self.action_result, headers, stream_path) return if len(self.current_execution_id) == 0: print("EXECUTIONID env not defined") - action_result["result"] = "Error in setup ENV: EXECUTIONID not defined" - self.send_result(action_result, headers, stream_path) + self.action_result["result"] = "Error in setup ENV: EXECUTIONID not defined" + self.send_result(self.action_result, headers, stream_path) return @@ -922,21 +932,21 @@ class AppBase: except json.decoder.JSONDecodeError: pass - action_result["result"] = "Bad result from backend: %d" % ret.status_code - self.send_result(action_result, headers, stream_path) + self.action_result["result"] = "Bad result from backend: %d" % ret.status_code + self.send_result(self.action_result, headers, stream_path) return except requests.exceptions.ConnectionError as e: self.logger.info("Connectionerror: %s" % e) - action_result["result"] = "Connection error during startup: %s" % e - self.send_result(action_result, headers, stream_path) + self.action_result["result"] = "Connection error during startup: %s" % e + self.send_result(self.action_result, headers, stream_path) return else: try: fullexecution = json.loads(self.full_execution) except json.decoder.JSONDecodeError as e: print("Json decode execution error: %s" % e) - action_result["result"] = "Json error during startup: %s" % e - self.send_result(action_result, headers, stream_path) + self.action_result["result"] = "Json error during startup: %s" % e + self.send_result(self.action_result, headers, stream_path) return print("") @@ -1993,10 +2003,10 @@ class AppBase: if not branchcheck: self.logger.info("Failed one or more branch conditions.") - action_result["result"] = tmpresult - action_result["status"] = "SKIPPED" + self.action_result["result"] = tmpresult + self.action_result["status"] = "SKIPPED" try: - ret = requests.post("%s%s" % (self.base_url, stream_path), headers=headers, json=action_result) + ret = requests.post("%s%s" % (self.base_url, stream_path), headers=headers, json=self.action_result) self.logger.info("Result: %d" % ret.status_code) if ret.status_code != 200: self.logger.info(ret.text) @@ -2021,8 +2031,8 @@ class AppBase: func = getattr(self, actionname, None) if func == None: self.logger.debug(f"Failed executing {actionname} because func is None.") - action_result["status"] = "FAILURE" - action_result["result"] = "Function %s doesn't exist." % actionname + self.action_result["status"] = "FAILURE" + self.action_result["result"] = "Function %s doesn't exist." % actionname elif callable(func): try: if len(action["parameters"]) < 1: @@ -2385,9 +2395,9 @@ class AppBase: print("LENGTH OF ARR: %d" % len(resultarray)) if len(resultarray) == 0: print("[WARNING] Returning empty array because the array length to be looped is 0 (0)") - action_result["status"] = "SUCCESS" - action_result["result"] = "[]" - self.send_result(action_result, headers, stream_path) + self.action_result["status"] = "SUCCESS" + self.action_result["result"] = "[]" + self.send_result(self.action_result, headers, stream_path) return #print("RESULTARRAY: %s" % resultarray) @@ -2531,10 +2541,10 @@ class AppBase: params = new_params[0] else: print("[WARNING] SHOULD STOP EXECUTION BECAUSE FIELDS AREN'T UNIQUE") - action_result["status"] = "SKIPPED" - action_result["result"] = f"A non-unique value was found" - action_result["completed_at"] = int(time.time()) - self.send_result(action_result, headers, stream_path) + self.action_result["status"] = "SKIPPED" + self.action_result["result"] = f"A non-unique value was found" + self.action_result["completed_at"] = int(time.time()) + self.send_result(self.action_result, headers, stream_path) return print("[INFO] Running normal execution (not loop)\n") @@ -2764,46 +2774,46 @@ class AppBase: print("Normal result - no list?") result = results - action_result["status"] = "SUCCESS" - action_result["result"] = str(result) - if action_result["result"] == "": - action_result["result"] = result + self.action_result["status"] = "SUCCESS" + self.action_result["result"] = str(result) + if self.action_result["result"] == "": + self.action_result["result"] = result self.logger.debug(f"Executed {action['label']}-{action['id']}")#with result: {result}") #self.logger.debug(f"Data: %s" % action_result) except TypeError as e: print("TypeError issue: %s" % e) - action_result["status"] = "FAILURE" - action_result["result"] = "TypeError: %s" % str(e) + self.action_result["status"] = "FAILURE" + self.action_result["result"] = "TypeError: %s" % str(e) else: print("Function %s doesn't exist?" % action["name"]) self.logger.error(f"App {self.__class__.__name__}.{action['name']} is not callable") - action_result["status"] = "FAILURE" - action_result["result"] = "Function %s is not callable." % actionname + self.action_result["status"] = "FAILURE" + self.action_result["result"] = "Function %s is not callable." % actionname # https://ptb.discord.com/channels/747075026288902237/882017498550112286/882043773138382890 except (requests.exceptions.RequestException, TimeoutError) as e: print(f"Failed to execute request: {e}") self.logger.exception(f"Failed to execute {e}-{action['id']}") - action_result["status"] = "SUCCESS" + self.action_result["status"] = "SUCCESS" try: - action_result["result"] = json.dumps({ + self.action_result["result"] = json.dumps({ "success": False, "reason": f"Request error - failing silently. Details: {e}" }) except json.decoder.JSONDecodeError as e: - action_result["result"] = f"Request error: {e}" + self.action_result["result"] = f"Request error: {e}" except Exception as e: print(f"Failed to execute: {e}") self.logger.exception(f"Failed to execute {e}-{action['id']}") - action_result["status"] = "FAILURE" - action_result["result"] = f"General exception: {e}" + self.action_result["status"] = "FAILURE" + self.action_result["result"] = f"General exception: {e}" - action_result["completed_at"] = int(time.time()) + self.action_result["completed_at"] = int(time.time()) # Send the result :) - self.send_result(action_result, headers, stream_path) + self.send_result(self.action_result, headers, stream_path) return @classmethod diff --git a/backend/app_sdk/build.sh b/backend/app_sdk/build.sh index 85b1b238..30560f50 100644 --- a/backend/app_sdk/build.sh +++ b/backend/app_sdk/build.sh @@ -3,7 +3,7 @@ ### DEFAULT NAME=shuffle-app_sdk -VERSION=0.9.19 +VERSION=0.9.20 docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force docker build . -f Dockerfile -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index 8a2ff410..cf113e8e 100644 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -9,7 +9,6 @@ import { useTheme } from '@material-ui/core/styles'; import YAML from 'yaml' import {Link} from 'react-router-dom'; -import ReactJson from 'react-json-view' import { useAlert } from "react-alert"; import Dropzone from '../components/Dropzone'; @@ -620,15 +619,6 @@ const Apps = (props) => { ) })} - {/* - - */} ) } diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index 3b9f466b..cec08ba1 100644 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -6,7 +6,7 @@ import {BrowserView, MobileView} from "react-device-detect"; import {Link} from 'react-router-dom'; import {Tooltip, Divider, Button, Menu, MenuItem, Typography, Paper, List} from '@material-ui/core'; -import {Edit as EditIcon} from '@material-ui/icons'; +import {Link as LinkIcon, Edit as EditIcon} from '@material-ui/icons'; const Body = { maxWidth: '1000px', @@ -28,6 +28,7 @@ const Docs = (props) => { const { globalUrl, selectedDoc, serverside, isMobile, } = props; const theme = useTheme(); + const [mobile, setMobile] = useState(isMobile === true ? true : false); const [data, setData] = useState(""); const [firstrequest, setFirstrequest] = useState(true); const [list, setList] = useState([]); @@ -107,14 +108,21 @@ const Docs = (props) => { if (firstrequest) { setFirstrequest(false) + if (!serverside) { + if (window.innerWidth < 768) { + setMobile(true) + } + } if (selectedDoc !== undefined) { setData(selectedDoc.reason) setList(selectedDoc.list) setListLoaded(true) } else { - fetchDocList() - fetchDocs(props.match.params.key) + if (!serverside) { + fetchDocList() + fetchDocs(props.match.params.key) + } } } @@ -194,10 +202,10 @@ const Docs = (props) => { const markdownStyle = { color: "rgba(255, 255, 255, 0.65)", flex: "1", - maxWidth: isMobile ? "100%" : 750, + maxWidth: mobile ? "100%" : 750, overflow: "hidden", paddingBottom: 200, - marginLeft: isMobile ? 0 : 275, + marginLeft: mobile ? 0 : 275, } function OuterLink(props) { @@ -221,34 +229,39 @@ const Docs = (props) => { ) } - function Heading(props) { + const Heading = (props) => { const element = React.createElement(`h${props.level}`, {style: {marginTop: 50}}, props.children) + const [hover, setHover] = useState(false) var extraInfo = "" if (props.level === 1) { extraInfo =
- - - - - -
- + {mobile ? null : + + + + + + } + {mobile ? null : +
+ } + {selectedMeta.read_time} minute{selectedMeta.read_time === 1 ? "" : "s"} to read
- {selectedMeta.contributors === undefined || selectedMeta.contributors === null ? "" : + {mobile || selectedMeta.contributors === undefined || selectedMeta.contributors === null ? "" :
{selectedMeta.contributors.slice(0,7).map((data, index) => { return ( - {data.url} + {data.url} ) @@ -260,9 +273,20 @@ const Docs = (props) => { } return ( - + { + setHover(true) + }} > {props.level !== 1 ? : null} {element} + {/*hover ? {setHover(true)}} style={{cursor: "pointer", display: "inline", }} onClick={() => { + window.location.href += "#hello" + console.log(window.location) + //window.history.pushState('page2', 'Title', '/page2.php'); + //window.history.replaceState('page2', 'Title', '/page2.php'); + }} /> + : "" + */} {extraInfo} ) @@ -345,6 +369,10 @@ const Docs = (props) => { > {list.map((data, index) => { const item = data.name + if (item === undefined) { + return null + } + const path = "/docs/"+item const newname = item.charAt(0).toUpperCase()+item.substring(1).split("_").join(" ").split("-").join(" ") return ( diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 58dd9625..2d3150dc 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -12,7 +12,6 @@ import {DataGrid, GridToolbarContainer, GridDensitySelector, GridToolbar} from ' //import JSONPretty from 'react-json-pretty'; //import JSONPrettyMon from 'react-json-pretty/dist/monikai' -import ReactJson from 'react-json-view' import Dropzone from '../components/Dropzone'; import {Link} from 'react-router-dom'; @@ -1372,181 +1371,11 @@ const Workflows = (props) => { return string.split(search).join(replace); } - const resultsPaper = (data) => { - var boxWidth = "2px" - var boxColor = "orange" - if (data.status === "ABORTED" || data.status === "UNFINISHED" || data.status === "FAILURE"){ - boxColor = "red" - } else if (data.status === "FINISHED" || data.status === "SUCCESS") { - boxColor = "green" - } else if (data.status === "SKIPPED" || data.status === "EXECUTING") { - boxColor = "yellow" - } else { - boxColor = "green" - } - var t = new Date(data.started_at*1000) - var showResult = data.result.trim() - const validate = validateJson(showResult) - - if (validate.valid) { - showResult = - } else { - // FIXME - have everything parsed as json, either just for frontend - // or in the backend? - /* - const newdata = {"result": data.result} - showResult = - */ - } - - return ( - {}}> -
-
- - - -

Name: {data.action.label}

-
- - App: {data.action.app_name}, Version: {data.action.app_version} - - - Action: {data.action.name}, Environment: {data.action.environment}, Status: {data.status} - -
- - Started: {t.toISOString()} - -
- -
- - {showResult} - -
-
-
-
- ) - } - - const resultsHandler = Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.results !== null ? -
- {selectedExecution.results.sort((a, b) => a.started_at - b.started_at).map((data, index) => { - return ( -
- {resultsPaper(data)} -
- ) - })} -
- : -
- No results yet -
const resultsLength = Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.results !== null ? selectedExecution.results.length : 0 - const ExecutionDetails = () => { - var starttime = new Date(selectedExecution.started_at*1000) - var endtime = new Date(selectedExecution.started_at*1000) - var parsedArgument = selectedExecution.execution_argument - if (selectedExecution.execution_argument !== undefined && selectedExecution.execution_argument.length > 0) { - parsedArgument = replaceAll(parsedArgument, " None", " \"None\""); - } - - var arg = null - if (selectedExecution.execution_argument !== undefined && selectedExecution.execution_argument.length > 0) { - var showResult = selectedExecution.execution_argument.trim() - const validate = validateJson(showResult) - - arg = validate.valid ? - - : showResult - } - - var lastresult = null - if (selectedExecution.result !== undefined && selectedExecution.result.length > 0) { - var showResult = selectedExecution.result.trim() - const validate = validateJson(showResult) - lastresult = validate.valid ? - - : showResult - } - - /* -
- ID: {selectedExecution.execution_id} -
-
- Last node: {selectedExecution.workflow.actions.find(data => data.id === selectedExecution.last_node).actions[0].label} -
- */ - if (Object.getOwnPropertyNames(selectedExecution).length > 0 && selectedExecution.workflow.actions !== null) { - return ( -
-
- Status: {selectedExecution.status} -
-
- Started: {starttime.toISOString()} -
-
- Finished: {endtime.toISOString()} -
- {/* -
- Last Result: {lastresult} -
- */} -
- {arg} -
- - {resultsHandler} -
- ) - } - - return ( - executionLoading ? -
- -
- : -

- There are no executiondetails yet. Click "execute" to run your first one. -

- - ) - } // Can create and set workflows const setNewWorkflow = (name, description, tags, defaultReturnValue, editingWorkflow, redirect) => {