Merge branch 'nightly' of https://github.com/Shuffle/Shuffle into automation
This commit is contained in:
@@ -74,6 +74,7 @@ import {
|
||||
|
||||
|
||||
import {
|
||||
Storage as StorageIcon,
|
||||
Code as CodeIcon,
|
||||
Folder as FolderIcon,
|
||||
VerifiedUser as VerifiedUserIcon,
|
||||
@@ -503,7 +504,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
const [allRevisions, setAllRevisions] = useState([])
|
||||
const [menuPosition, setMenuPosition] = useState(null);
|
||||
const [showDropdown, setShowDropdown] = React.useState(false);
|
||||
const [subflowActionList, setSubflowActionList] = React.useState([]);
|
||||
const [triggerActionList, setTriggerActionList] = React.useState([]);
|
||||
|
||||
const [apps, setApps] = React.useState([]);
|
||||
const [filteredApps, setFilteredApps] = React.useState([]);
|
||||
@@ -574,11 +575,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}, [editWorkflowModalOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTrigger !== undefined && selectedTrigger?.parameters !== undefined && selectedTrigger?.parameters !== null && selectedTrigger?.parameters?.length > 1) {
|
||||
// Right now just setting for the subflow
|
||||
setSelectedTriggerValue(selectedTrigger?.parameters[1]?.value)
|
||||
}
|
||||
}, [selectedTrigger])
|
||||
if(selectedTrigger?.trigger_type === "SUBFLOW"){
|
||||
setSelectedTriggerValue(workflow.triggers[selectedTriggerIndex].parameters[1].value || "")
|
||||
} else if(selectedTrigger?.trigger_type === "USERINPUT"){
|
||||
setSelectedTriggerValue(workflow.triggers[selectedTriggerIndex].parameters[0].value || "Do you want to continue the workflow? Start parameters: $exec")
|
||||
}
|
||||
}, [selectedTriggerIndex, selectedTrigger, workflow])
|
||||
|
||||
useEffect(() => {
|
||||
if(selectedEdge && Object.keys(selectedEdge).length > 0){
|
||||
@@ -1136,23 +1138,66 @@ const AngularWorkflow = (defaultprops) => {
|
||||
useEffect(() => {
|
||||
// if (subflowActionList.length === 0) {
|
||||
const newActionList = [];
|
||||
// FIXME: Have previous execution values in here
|
||||
newActionList.push({
|
||||
type: "Runtime Argument",
|
||||
name: "Runtime Argument",
|
||||
value: "$exec",
|
||||
highlight: "exec",
|
||||
autocomplete: "exec",
|
||||
example: "hello",
|
||||
})
|
||||
newActionList.push({
|
||||
type: "Shuffle Database",
|
||||
name: "Shuffle Database",
|
||||
|
||||
|
||||
if (workflowExecutions.length > 0) {
|
||||
for (let execution of workflowExecutions) {
|
||||
const execArg = execution.execution_argument;
|
||||
if (execArg && execArg.length > 0) {
|
||||
const valid = validateJson(execArg);
|
||||
if (valid.valid) {
|
||||
newActionList.push({
|
||||
type: "Runtime Argument",
|
||||
name: "Runtime Argument",
|
||||
value: "$exec",
|
||||
highlight: "exec",
|
||||
autocomplete: "exec",
|
||||
example: valid.result,
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add default Runtime Argument if none were added
|
||||
if (newActionList.length === 0) {
|
||||
newActionList.push({
|
||||
type: "Runtime Argument",
|
||||
name: "Runtime Argument",
|
||||
value: "$exec",
|
||||
highlight: "exec",
|
||||
autocomplete: "exec",
|
||||
example: "",
|
||||
})
|
||||
}
|
||||
// Add Shuffle DB with cache keys if available
|
||||
let cacheKey = {
|
||||
type: "Shuffle DB",
|
||||
name: "Shuffle DB",
|
||||
value: "$shuffle_cache",
|
||||
highlight: "shuffle_db",
|
||||
highlight: "shuffle_cache",
|
||||
autocomplete: "shuffle_cache",
|
||||
example: "hello",
|
||||
})
|
||||
example: "Hello",
|
||||
}
|
||||
|
||||
if (listCache?.keys?.length > 0) {
|
||||
cacheKey.example = {};
|
||||
for (let item of listCache.keys) {
|
||||
if (item.key) {
|
||||
let itemValue = item.value ?? "";
|
||||
if (itemValue.length > 10000) {
|
||||
itemValue = "";
|
||||
}
|
||||
cacheKey.example[item.key.split(" ").join("_")] = { value: itemValue };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newActionList.push(cacheKey);
|
||||
// FIXME: Have previous execution values in here
|
||||
|
||||
if (
|
||||
workflow.workflow_variables !== null &&
|
||||
workflow.workflow_variables !== undefined &&
|
||||
@@ -1216,7 +1261,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
const validated = validateJson(foundResult.result)
|
||||
if (validated.valid) {
|
||||
exampledata = validateJson.result
|
||||
exampledata = validated.result
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -1234,7 +1279,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
}
|
||||
}
|
||||
|
||||
setSubflowActionList(newActionList);
|
||||
setTriggerActionList(newActionList);
|
||||
}, [workflow.workflow_variables, workflow.execution_variables, workflow, selectedTrigger]);
|
||||
|
||||
|
||||
@@ -1687,7 +1732,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
if (filter === undefined || filter === null || filter.toUpperCase() === "ALL") {
|
||||
|
||||
// Check for
|
||||
if (executionFilter !== undefined && executionFilter !== null && executionFilter.length > 0) {
|
||||
if (executionFilter !== undefined && executionFilter !== null && executionFilter.length > 0 && filter !== "ALL") {
|
||||
filter = executionFilter
|
||||
} else {
|
||||
filter = "ALL"
|
||||
@@ -2715,10 +2760,12 @@ const AngularWorkflow = (defaultprops) => {
|
||||
return newExample
|
||||
}
|
||||
|
||||
/*
|
||||
for (var i = 0; i < found.length; i++) {
|
||||
//newExample = newExample.replace(found[i], "REQUIRED")
|
||||
newExample = newExample.replace(found[i], "REPLACE_ME")
|
||||
}
|
||||
*/
|
||||
|
||||
return newExample
|
||||
}
|
||||
@@ -7116,7 +7163,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
data: newcybranch,
|
||||
};
|
||||
|
||||
console.log("SHOULD STITCH WITH STARTNODE");
|
||||
cy.add(edgeToBeAdded);
|
||||
}
|
||||
|
||||
@@ -12416,13 +12462,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
|
||||
// Get parent nodes and their data
|
||||
if (selectedEdge) {
|
||||
|
||||
let nodeId;
|
||||
if (type === "source") {
|
||||
nodeId = selectedEdge.source;
|
||||
} else if (type === "destination") {
|
||||
nodeId = selectedEdge.target;
|
||||
}
|
||||
const nodeId = selectedEdge.target;
|
||||
|
||||
const node = cy.getElementById(nodeId);
|
||||
if (node?.length > 0) {
|
||||
@@ -13457,7 +13497,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
Shuffle AI
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
What you write here will be fed to the Shuffle AI to generate a change for the selected action or field. Best used for when you are stuck with formatting. Uses your AI credits (resets monthly). Alpha feature. Please give feedback to support@shuffler.io {"<"}3
|
||||
What you write here will be fed to the Shuffle AI to generate a change for the selected action or field. Best used for when you are stuck with formatting. Uses your AI credits (resets monthly). <b>Beta feature.</b> Please give feedback to support@shuffler.io {"<"}3
|
||||
|
||||
</Typography>
|
||||
<TextField
|
||||
@@ -13784,6 +13824,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
setSourceValue({});
|
||||
setConditionValue({});
|
||||
setDestinationValue({});
|
||||
navigate("")
|
||||
}}
|
||||
color="secondary"
|
||||
>
|
||||
@@ -13794,6 +13835,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setSelectedEdge({});
|
||||
navigate("")
|
||||
|
||||
var data = {
|
||||
condition: conditionValue,
|
||||
@@ -14618,43 +14660,62 @@ const AngularWorkflow = (defaultprops) => {
|
||||
};
|
||||
|
||||
const handleItemClick = (values) => {
|
||||
console.log("VALUES: ", values)
|
||||
if (values === undefined || values === null || values.length === 0) {
|
||||
return;
|
||||
console.log("VALUES: ", values)
|
||||
if (values === undefined || values === null || values.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the base autocomplete value and normalize it
|
||||
let toComplete = values[0].autocomplete.toLowerCase().replaceAll(" ", "_");
|
||||
|
||||
// Add $ prefix if not already present
|
||||
if (!toComplete.startsWith("$")) {
|
||||
toComplete = "$" + toComplete;
|
||||
}
|
||||
|
||||
// Add any additional path components
|
||||
for (let key in values) {
|
||||
if (key === "0" || !values[key].autocomplete) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toComplete += values[key].autocomplete;
|
||||
}
|
||||
|
||||
/*
|
||||
workflow.triggers[selectedTriggerIndex].parameters[1].value
|
||||
.trim()
|
||||
.endsWith("$")
|
||||
? values[0].autocomplete
|
||||
: "$" + values[0].autocomplete;
|
||||
var foundField;
|
||||
// Update the field value
|
||||
if(selectedTrigger?.trigger_type === "SUBFLOW"){
|
||||
foundField = document.getElementById("subflow_exec_field");
|
||||
}else if(selectedTrigger?.trigger_type === "USERINPUT"){
|
||||
foundField = document.getElementById("userinput_info_field");
|
||||
}
|
||||
|
||||
for (var key in values) {
|
||||
if (key === 0 || values[key].autocomplete.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (foundField) {
|
||||
// Get current cursor position
|
||||
const cursorPos = foundField.selectionStart;
|
||||
const currentValue = foundField.value;
|
||||
|
||||
toComplete += values[key].autocomplete
|
||||
}
|
||||
*/
|
||||
|
||||
if (selectedTrigger.name === "Shuffle Workflow") {
|
||||
const toComplete = workflow?.triggers?.[selectedTriggerIndex]?.parameters?.[1]?.value + "$" + values[0]?.autocomplete
|
||||
// selectedTrigger.parameters[1].value = toComplete
|
||||
workflow.triggers[selectedTriggerIndex].parameters[1].value = toComplete
|
||||
const foundfield = document.getElementById("subflow_exec_field")
|
||||
if (foundfield !== undefined && foundfield !== null) {
|
||||
foundfield.value = toComplete
|
||||
}
|
||||
setWorkflow(workflow)
|
||||
// Insert the new value at cursor position
|
||||
const newValue = currentValue.slice(0, cursorPos) + toComplete + currentValue.slice(cursorPos);
|
||||
foundField.value = newValue;
|
||||
|
||||
// Update state
|
||||
setSelectedTriggerValue(newValue);
|
||||
if(selectedTrigger?.trigger_type === "SUBFLOW"){
|
||||
workflow.triggers[selectedTriggerIndex].parameters[1].value = newValue
|
||||
}else if(selectedTrigger?.trigger_type === "USERINPUT"){
|
||||
workflow.triggers[selectedTriggerIndex].parameters[0].value = newValue
|
||||
}
|
||||
|
||||
setUpdate(Math.random());
|
||||
setShowDropdown(false);
|
||||
setMenuPosition(null);
|
||||
};
|
||||
// Set cursor position after inserted text
|
||||
foundField.setSelectionRange(cursorPos + toComplete.length, cursorPos + toComplete.length);
|
||||
}
|
||||
|
||||
setWorkflow(workflow);
|
||||
setUpdate(Math.random());
|
||||
setShowDropdown(false);
|
||||
setMenuPosition(null);
|
||||
};
|
||||
|
||||
const subflowtypes = [
|
||||
{
|
||||
@@ -14681,7 +14742,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
workflow.triggers[triggerIndex].parameters[paramIndex].value = newData;
|
||||
|
||||
// Update workflow state to trigger re-render
|
||||
setWorkflow({...workflow});
|
||||
setWorkflow(workflow);
|
||||
setSelectedTriggerValue(newData)
|
||||
setLastSaved(false);
|
||||
}
|
||||
@@ -15171,7 +15232,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
"name": workflow.triggers[selectedTriggerIndex].parameters[1].name,
|
||||
"value": parsedvalue,
|
||||
"field_number": 1,
|
||||
"actionlist": subflowActionList,
|
||||
"actionlist": triggerActionList,
|
||||
"field_id": "subflow_exec_field",
|
||||
})
|
||||
}}
|
||||
@@ -15216,15 +15277,13 @@ const AngularWorkflow = (defaultprops) => {
|
||||
fullWidth
|
||||
color="primary"
|
||||
placeholder="Some execution data"
|
||||
value={
|
||||
selectedTriggerValue
|
||||
}
|
||||
value={selectedTriggerValue || ""}
|
||||
onChange={(e) => {
|
||||
setLastSaved(false)
|
||||
setSelectedTriggerValue(e.target.value)
|
||||
}}
|
||||
onBlur={() => {
|
||||
workflow.triggers[selectedTriggerIndex].parameters[1].value = selectedTriggerValue
|
||||
onBlur={(e) => {
|
||||
workflow.triggers[selectedTriggerIndex].parameters[1].value = e.target.value
|
||||
setWorkflow(workflow)
|
||||
}}
|
||||
/>
|
||||
@@ -15242,16 +15301,17 @@ const AngularWorkflow = (defaultprops) => {
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{subflowActionList.map((innerdata) => {
|
||||
{triggerActionList.map((innerdata) => {
|
||||
const icon =
|
||||
innerdata.type === "action" ? (
|
||||
<AppsIcon style={{ marginRight: 10 }} />
|
||||
) : innerdata.type === "workflow_variable" ||
|
||||
innerdata.type === "execution_variable" ? (
|
||||
<FavoriteBorderIcon style={{ marginRight: 10 }} />
|
||||
) : (
|
||||
<ScheduleIcon style={{ marginRight: 10 }} />
|
||||
);
|
||||
) : innerdata.type === "Shuffle DB" ?
|
||||
<StorageIcon style={{ marginRight: 10, }} />
|
||||
:
|
||||
<ScheduleIcon style={{ marginRight: 10 }} />
|
||||
|
||||
const handleExecArgumentHover = (inside) => {
|
||||
var exec_text_field = document.getElementById(
|
||||
@@ -16687,21 +16747,43 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</div>
|
||||
*/}
|
||||
<div style={{ flex: "6", marginTop: 10, }}>
|
||||
<div
|
||||
style={{
|
||||
marginTop: "20px",
|
||||
marginBottom: "7px",
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: "10" }}>
|
||||
<b>Information</b>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
The information you want to show the user. Supports variables. Supports Markdown & HTML.
|
||||
</Typography>
|
||||
</div>
|
||||
<div style={{ marginTop: "20px", marginBottom: "5px", display: "flex", width: "100%", flexDirection: "column" }}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "100%" }}>
|
||||
<b>Information</b>
|
||||
<Tooltip title="Expand editor window" placement="top">
|
||||
<IconButton
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
setCodeEditorModalOpen(true)
|
||||
setActiveDialog("codeeditor")
|
||||
var parsedvalue = workflow?.triggers[selectedTriggerIndex]?.parameters[0]?.value
|
||||
|
||||
navigate(`?trigger_id=${selectedTrigger.id}&trigger_field=${"alertinfo"}&trigger_name=${selectedTrigger.label}`)
|
||||
setEditorData({
|
||||
"name": workflow.triggers[selectedTriggerIndex].parameters[0].name,
|
||||
"value": parsedvalue,
|
||||
"field_number": 0,
|
||||
"actionlist": triggerActionList,
|
||||
"field_id": "information_field",
|
||||
})
|
||||
}}
|
||||
>
|
||||
<OpenInFullIcon
|
||||
style={{
|
||||
color: "rgba(255,255,255,0.7)",
|
||||
height: 20,
|
||||
width: 20
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Typography color="textSecondary" sx={{fontSize: "13px"}}>
|
||||
The information you want to show the user. Supports variables. Supports Markdown & HTML.
|
||||
</Typography>
|
||||
</div>
|
||||
<TextField
|
||||
id="userinput_info_field"
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
borderRadius: theme.palette?.borderRadius,
|
||||
@@ -16709,19 +16791,347 @@ const AngularWorkflow = (defaultprops) => {
|
||||
InputProps={{
|
||||
style: {
|
||||
},
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<Tooltip title="Autocomplete text" placement="top">
|
||||
<AddCircleOutlineIcon
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={(event) => {
|
||||
setMenuPosition({
|
||||
top: event.pageY + 10,
|
||||
left: event.pageX + 10,
|
||||
});
|
||||
//setShowDropdownNumber(3)
|
||||
setShowDropdown(true);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
fullWidth
|
||||
rows="4"
|
||||
multiline
|
||||
defaultValue={
|
||||
workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers[selectedTriggerIndex].parameters !== undefined && workflow.triggers[selectedTriggerIndex].parameters.length > 0 && workflow.triggers[selectedTriggerIndex].parameters[0] !== undefined && workflow.triggers[selectedTriggerIndex].parameters[0].value !== undefined ? workflow.triggers[selectedTriggerIndex].parameters[0].value : ""
|
||||
}
|
||||
value={selectedTriggerValue}
|
||||
onChange={(e) => {
|
||||
setLastSaved(false)
|
||||
setSelectedTriggerValue(e.target.value)
|
||||
}}
|
||||
color="primary"
|
||||
placeholder=""
|
||||
onBlur={(e) => {
|
||||
setTriggerTextInformationWrapper(e.target.value);
|
||||
}}
|
||||
/>
|
||||
{!showDropdown ? null :
|
||||
<Menu
|
||||
anchorReference="anchorPosition"
|
||||
anchorPosition={menuPosition}
|
||||
onClose={() => {
|
||||
handleMenuClose();
|
||||
}}
|
||||
open={!!menuPosition}
|
||||
style={{
|
||||
border: `2px solid #FF8544`,
|
||||
color: "white",
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{triggerActionList.map((innerdata) => {
|
||||
const icon =
|
||||
innerdata.type === "action" ? (
|
||||
<AppsIcon style={{ marginRight: 10 }} />
|
||||
) : innerdata.type === "workflow_variable" ||
|
||||
innerdata.type === "execution_variable" ? (
|
||||
<FavoriteBorderIcon style={{ marginRight: 10 }} />
|
||||
) : innerdata.type === "Shuffle DB" ?
|
||||
<StorageIcon style={{ marginRight: 10, }} />
|
||||
:
|
||||
<ScheduleIcon style={{ marginRight: 10 }} />
|
||||
|
||||
const handleExecArgumentHover = (inside) => {
|
||||
var exec_text_field = document.getElementById(
|
||||
"execution_argument_input_field"
|
||||
);
|
||||
if (exec_text_field !== null) {
|
||||
if (inside) {
|
||||
exec_text_field.style.border = "2px solid #FF8544";
|
||||
} else {
|
||||
exec_text_field.style.border = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Also doing arguments
|
||||
if (
|
||||
workflow.triggers !== undefined &&
|
||||
workflow.triggers !== null &&
|
||||
workflow.triggers.length > 0
|
||||
) {
|
||||
for (let triggerkey in workflow.triggers) {
|
||||
const item = workflow.triggers[triggerkey];
|
||||
|
||||
if (cy !== undefined && cy !== null) {
|
||||
var node = cy.getElementById(item.id);
|
||||
if (node.length > 0) {
|
||||
if (inside) {
|
||||
node.addClass("shuffle-hover-highlight");
|
||||
} else {
|
||||
node.removeClass("shuffle-hover-highlight");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleActionHover = (inside, actionId) => {
|
||||
if (cy !== undefined && cy !== null) {
|
||||
var node = cy.getElementById(actionId);
|
||||
if (node.length > 0) {
|
||||
if (inside) {
|
||||
node.addClass("shuffle-hover-highlight");
|
||||
} else {
|
||||
node.removeClass("shuffle-hover-highlight");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseover = () => {
|
||||
if (innerdata.type === "Runtime Argument") {
|
||||
handleExecArgumentHover(true);
|
||||
} else if (innerdata.type === "action") {
|
||||
handleActionHover(true, innerdata.id);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseOut = () => {
|
||||
if (innerdata.type === "Runtime Argument") {
|
||||
handleExecArgumentHover(false);
|
||||
} else if (innerdata.type === "action") {
|
||||
handleActionHover(false, innerdata.id);
|
||||
}
|
||||
};
|
||||
|
||||
var parsedPaths = [];
|
||||
|
||||
if (innerdata.type === "workflow_variable") {
|
||||
// Try to parse the value if it's a string that could be JSON
|
||||
if (typeof innerdata.value === "string") {
|
||||
try {
|
||||
const parsedValue = JSON.parse(innerdata.value)
|
||||
if (typeof parsedValue === "object") {
|
||||
parsedPaths = GetParsedPaths(parsedValue, "");
|
||||
}
|
||||
} catch (e) {
|
||||
// Not valid JSON, use the value directly
|
||||
parsedPaths = GetParsedPaths(innerdata.value, "");
|
||||
}
|
||||
} else if (typeof innerdata.value === "object") {
|
||||
parsedPaths = GetParsedPaths(innerdata.value, "");
|
||||
}
|
||||
} else if (typeof innerdata.example === "object") {
|
||||
parsedPaths = GetParsedPaths(innerdata.example, "");
|
||||
}
|
||||
|
||||
const coverColor = "#82ccc3"
|
||||
|
||||
return parsedPaths.length > 0 ? (
|
||||
<span>
|
||||
{/*
|
||||
<NestedMenuItem
|
||||
key={innerdata.name}
|
||||
label={
|
||||
<div style={{ display: "flex" }}>
|
||||
{icon} {innerdata.name}
|
||||
</div>
|
||||
}
|
||||
parentMenuOpen={!!menuPosition}
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
minWidth: 250,
|
||||
}}
|
||||
onClick={() => {
|
||||
handleItemClick([innerdata]);
|
||||
}}
|
||||
>
|
||||
{parsedPaths.map((pathdata, index) => {
|
||||
// FIXME: Should be recursive in here
|
||||
const icon =
|
||||
pathdata.type === "value" ? (
|
||||
<VpnKeyIcon style={iconStyle} />
|
||||
) : pathdata.type === "list" ? (
|
||||
<FormatListNumberedIcon style={iconStyle} />
|
||||
) : (
|
||||
<ExpandMoreIcon style={iconStyle} />
|
||||
)
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={pathdata.name}
|
||||
style={{
|
||||
backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
minWidth: 250,
|
||||
}}
|
||||
value={pathdata}
|
||||
onMouseOver={() => { }}
|
||||
onClick={() => {
|
||||
handleItemClick([innerdata, pathdata]);
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={`Ex. value: ${pathdata.value}`}
|
||||
placement="left"
|
||||
>
|
||||
<div style={{ display: "flex" }}>
|
||||
{icon} {pathdata.name}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</NestedMenuItem>
|
||||
*/}
|
||||
|
||||
<NestedMenuItem
|
||||
key={innerdata.name}
|
||||
label={
|
||||
<div style={{ display: "flex", marginLeft: 0, }}>
|
||||
{icon} {innerdata.name}
|
||||
</div>
|
||||
}
|
||||
parentMenuOpen={!!menuPosition}
|
||||
style={{
|
||||
color: "white",
|
||||
minWidth: 250,
|
||||
maxWidth: 250,
|
||||
maxHeight: 50,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onClick={() => {
|
||||
console.log(innerdata.example)
|
||||
handleItemClick([innerdata]);
|
||||
}}
|
||||
>
|
||||
<Paper style={{ minHeight: 500, maxHeight: 500, minWidth: 275, maxWidth: 275, position: "fixed", top: menuPosition?.top - 200, left: menuPosition?.left - 455, padding: "10px 0px 10px 10px", overflow: "hidden", overflowY: "auto", border: "1px solid rgba(255,255,255,0.3)", }}>
|
||||
|
||||
<MenuItem
|
||||
key={innerdata.name}
|
||||
style={{
|
||||
// backgroundColor: theme.palette.inputColor,
|
||||
marginLeft: 15,
|
||||
color: "white",
|
||||
minWidth: 250,
|
||||
maxWidth: 250,
|
||||
padding: 0,
|
||||
position: "relative",
|
||||
}}
|
||||
value={innerdata}
|
||||
onMouseOver={() => {
|
||||
//console.log("HOVER: ", pathdata);
|
||||
}}
|
||||
onClick={() => {
|
||||
handleItemClick([innerdata]);
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" style={{ paddingBottom: 5 }}>
|
||||
{innerdata.name}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
|
||||
{parsedPaths.map((pathdata, index) => {
|
||||
// FIXME: Should be recursive in here
|
||||
//<VpnKeyIcon style={iconStyle} />
|
||||
const icon =
|
||||
pathdata.type === "value" ? (
|
||||
<span style={{ marginLeft: 9, }} />
|
||||
) : pathdata.type === "list" ? (
|
||||
<FormatListNumberedIcon style={{ marginLeft: 9, marginRight: 10, }} />
|
||||
) : (
|
||||
<CircleIcon style={{ marginLeft: 9, marginRight: 10, color: coverColor }} />
|
||||
);
|
||||
//<ExpandMoreIcon style={iconStyle} />
|
||||
|
||||
const indentation_count = (pathdata.name.match(/\./g) || []).length + 1
|
||||
const baseIndent = <div style={{ marginLeft: 20, height: 30, width: 1, backgroundColor: coverColor, }} />
|
||||
//const boxPadding = pathdata.type === "object" ? "10px 0px 0px 0px" : 0
|
||||
const boxPadding = 0
|
||||
const namesplit = pathdata.name.split(".")
|
||||
const newname = namesplit[namesplit.length - 1]
|
||||
return (
|
||||
<MenuItem
|
||||
key={pathdata.name}
|
||||
style={{
|
||||
// backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
minWidth: 250,
|
||||
maxWidth: 250,
|
||||
padding: boxPadding,
|
||||
}}
|
||||
value={pathdata}
|
||||
onMouseOver={() => {
|
||||
//console.log("HOVER: ", pathdata);
|
||||
}}
|
||||
onClick={() => {
|
||||
handleItemClick([innerdata, pathdata]);
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={`Ex. value: ${pathdata.value}`}
|
||||
placement="left"
|
||||
>
|
||||
<div style={{ display: "flex", height: 30, }}>
|
||||
{Array(indentation_count).fill().map((subdata, subindex) => {
|
||||
return (
|
||||
baseIndent
|
||||
)
|
||||
})}
|
||||
{icon} {newname}
|
||||
{pathdata.type === "list" ? <SquareFootIcon style={{ marginleft: 10, }} onClick={(e) => {
|
||||
|
||||
}} /> : null}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Paper>
|
||||
</NestedMenuItem>
|
||||
</span>
|
||||
) : (
|
||||
<MenuItem
|
||||
key={innerdata.name}
|
||||
style={{
|
||||
// backgroundColor: theme.palette.inputColor,
|
||||
color: "white",
|
||||
}}
|
||||
value={innerdata}
|
||||
onMouseOver={() => handleMouseover()}
|
||||
onMouseOut={() => {
|
||||
handleMouseOut();
|
||||
}}
|
||||
onClick={() => {
|
||||
handleItemClick([innerdata]);
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
color="primary"
|
||||
title={`Value: ${innerdata.value}`}
|
||||
placement="left"
|
||||
>
|
||||
<div style={{ display: "flex" }}>
|
||||
{icon} {innerdata.name}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
}
|
||||
<div
|
||||
style={{
|
||||
marginTop: "20px",
|
||||
@@ -19847,7 +20257,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={false}
|
||||
shouldCollapse={(jsonField) => {
|
||||
return collapseField(jsonField)
|
||||
}}
|
||||
@@ -20191,7 +20600,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={parsedCollapse}
|
||||
shouldCollapse={(jsonField) => {
|
||||
return collapseField(jsonField)
|
||||
}}
|
||||
@@ -21567,7 +21975,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={false}
|
||||
shouldCollapse={(jsonField) => {
|
||||
return collapseField(jsonField)
|
||||
}}
|
||||
@@ -21729,7 +22136,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
src={checked.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={data.value.length < 10000 ? false : true}
|
||||
shouldCollapse={(jsonField) => {
|
||||
return collapseField(jsonField)
|
||||
}}
|
||||
@@ -22155,7 +22561,6 @@ const AngularWorkflow = (defaultprops) => {
|
||||
src={validate.result}
|
||||
theme={theme.palette.jsonTheme}
|
||||
style={theme.palette.reactJsonStyle}
|
||||
collapsed={selectedResult.result.length < 10000 ? false : true}
|
||||
shouldCollapse={(jsonField) => {
|
||||
return collapseField(jsonField)
|
||||
}}
|
||||
@@ -22216,6 +22621,7 @@ const AngularWorkflow = (defaultprops) => {
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
{selectedResult.action.parameters !== null &&
|
||||
selectedResult.action.parameters !== undefined ? (
|
||||
|
||||
@@ -2906,7 +2906,7 @@ const AppExplorer = (props) => {
|
||||
const deduplicateByName = (array) => {
|
||||
const uniqueNames = {};
|
||||
return array.filter(item => {
|
||||
if (!item.hasOwnProperty('name') || !item.name.length) {
|
||||
if (!item?.hasOwnProperty('name') || !item?.name?.length) {
|
||||
return true
|
||||
}
|
||||
if (!uniqueNames[item.name]) {
|
||||
|
||||
@@ -52,12 +52,11 @@ const searchClient = algoliasearch(
|
||||
const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata, fetchApps, appsToShow, setAppsToShow, setUserApps, }) => {
|
||||
const navigate = useNavigate();
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000";
|
||||
const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`;
|
||||
//const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`;
|
||||
const appUrl = `/apps/${data.id}`
|
||||
|
||||
var canEditApp = userdata?.support ||
|
||||
userdata?.id === data?.owner ||
|
||||
(userdata?.admin === "true" && userdata?.active_org?.id === data?.reference_org) ||
|
||||
data?.contributors?.includes(userdata?.id)
|
||||
var canEditApp = userdata?.support || userdata?.id === data?.owner ||
|
||||
(userdata?.admin === "true" && userdata?.active_org?.id === data?.reference_org) || data?.contributors?.includes(userdata?.id)
|
||||
|
||||
const paperStyle = {
|
||||
backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#212121",
|
||||
@@ -71,7 +70,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)",
|
||||
marginBottom: 20,
|
||||
transition: "width 0.3s ease",
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid item xs={12} key={index}>
|
||||
@@ -133,6 +132,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
margin: "12px 0",
|
||||
fontFamily: theme?.typography?.fontFamily,
|
||||
}}>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
@@ -144,6 +144,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
maxWidth: "90%",
|
||||
gap: 8
|
||||
}}>
|
||||
|
||||
<div style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
@@ -152,6 +153,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
}}>
|
||||
{data.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style={{
|
||||
overflow: "hidden",
|
||||
@@ -162,6 +164,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
}}>
|
||||
{data.categories ? data.categories.join(", ") : "NA"}
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
@@ -187,6 +190,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Deactivate button */}
|
||||
{(currTab === 0 || currTab === 1) && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && (
|
||||
<div style={{
|
||||
@@ -222,6 +226,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
<Button
|
||||
disabled={data?.reference_org === userdata?.active_org?.id}
|
||||
className="deactivate-button"
|
||||
@@ -264,18 +269,6 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl,
|
||||
}
|
||||
} else {
|
||||
toast.success("App deactivated successfully. Will take effect on refresh..")
|
||||
|
||||
/*
|
||||
// This somehow didn't work
|
||||
if (appsToShow !== undefined && appsToShow !== null && appsToShow.length > 0) {
|
||||
const newApps = appsToShow?.filter((app) => app.id !== data.id)
|
||||
if (newApps !== undefined && newApps !== null && newApps.length > 0) {
|
||||
setAppsToShow(newApps)
|
||||
setUserApps(newApps)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -517,7 +510,6 @@ const Hits = ({
|
||||
fontFamily: theme?.typography?.fontFamily
|
||||
}}
|
||||
onClick={() => {
|
||||
console.log("App modal", data)
|
||||
handleAppClick(data);
|
||||
}}
|
||||
>
|
||||
@@ -645,6 +637,7 @@ const Hits = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
@@ -654,7 +647,7 @@ const Hits = ({
|
||||
}}>
|
||||
{hoverEffect === index && (
|
||||
<div>
|
||||
{allActivatedAppIds && allActivatedAppIds.includes(data.objectID) ? (
|
||||
{allActivatedAppIds && allActivatedAppIds?.includes(data.objectID) ? (
|
||||
<Button
|
||||
style={{
|
||||
width: 110,
|
||||
@@ -673,7 +666,9 @@ const Hits = ({
|
||||
}}>
|
||||
Deactivate
|
||||
</Button>
|
||||
|
||||
) : (
|
||||
|
||||
<Button
|
||||
style={{
|
||||
backgroundColor: "#FF8544",
|
||||
@@ -1303,6 +1298,8 @@ const Apps2 = (props) => {
|
||||
//console.log("Failed to get apps from localstorage: ", e)
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
fetch(globalUrl + "/api/v1/apps", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
|
||||
@@ -6,12 +6,9 @@ import classNames from "classnames";
|
||||
import theme from '../theme.jsx';
|
||||
import { useNavigate, Link, useParams } from "react-router-dom";
|
||||
|
||||
// react plugin used to create charts
|
||||
//import { Line, Bar } from "react-chartjs-2";
|
||||
//import { useAlert
|
||||
import { ToastContainer, toast } from "react-toastify"
|
||||
import Draggable from "react-draggable";
|
||||
import DashboardBarchart, { LoadStats } from '../components/DashboardBarchart.jsx';
|
||||
// import DashboardBarchart, { LoadStats } from '../components/DashboardBarchart.jsx';
|
||||
|
||||
import {
|
||||
Autocomplete,
|
||||
@@ -311,9 +308,13 @@ const RadialChart = ({keys, setSelectedCategory}) => {
|
||||
//axis={<RadialAxis type="category" />}
|
||||
}
|
||||
|
||||
|
||||
// 0x0elliot: not cleaning this up. this seems clearly experimental. not worth my time.
|
||||
|
||||
// This is the start of a dashboard that can be used.
|
||||
// What data do we fill in here? Idk
|
||||
const Dashboard = (props) => {
|
||||
|
||||
const { globalUrl, isLoggedIn } = props;
|
||||
//const alert = useAlert();
|
||||
const [bigChartData, setBgChartData] = useState("data1");
|
||||
@@ -397,7 +398,7 @@ const Dashboard = (props) => {
|
||||
if (foundQuery !== null && foundQuery !== undefined) {
|
||||
setSelectedUsecaseCategory(foundQuery)
|
||||
|
||||
const newitem = removeParam("selected", cursearch);
|
||||
const newitem = removeParam("selected", cursearch);
|
||||
navigate(curpath + newitem)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,9 +186,9 @@ const LoginDialog = (props) => {
|
||||
|
||||
if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) {
|
||||
console.log("RUN Welcome!!")
|
||||
setTimeout(() => {
|
||||
navigate("/welcome?tab=2")
|
||||
},200)
|
||||
setTimeout(() => {
|
||||
navigate("/welcome?tab=2")
|
||||
},200)
|
||||
// window.location.pathname = ""
|
||||
return
|
||||
}
|
||||
|
||||
+108
-111
@@ -427,11 +427,15 @@ const chipStyle = {
|
||||
color: "white",
|
||||
};
|
||||
|
||||
export const collapseField = (field) => {
|
||||
export const collapseField = (field, inputdata) => {
|
||||
if (field === undefined || field === null) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (field.namespace !== undefined && field.namespace !== null && field.namespace.length === 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (field.name === "headers" || field.name === "cookies") {
|
||||
return true
|
||||
}
|
||||
@@ -451,44 +455,44 @@ export const collapseField = (field) => {
|
||||
}
|
||||
|
||||
export const validateJson = (showResult) => {
|
||||
if (showResult === undefined || showResult === null) {
|
||||
return {
|
||||
valid: false,
|
||||
result: "",
|
||||
}
|
||||
}
|
||||
if (showResult === undefined || showResult === null) {
|
||||
return {
|
||||
valid: false,
|
||||
result: "",
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof showResult === 'string') {
|
||||
showResult = showResult.split(" False").join(" false")
|
||||
showResult = showResult.split(" True").join(" true")
|
||||
if (typeof showResult === 'string') {
|
||||
showResult = showResult.split(" False").join(" false")
|
||||
showResult = showResult.split(" True").join(" true")
|
||||
|
||||
showResult.replaceAll("False,", "false,")
|
||||
showResult.replaceAll("True,", "true,")
|
||||
}
|
||||
showResult.replaceAll("False,", "false,")
|
||||
showResult.replaceAll("True,", "true,")
|
||||
}
|
||||
|
||||
if (typeof showResult === "object" || typeof showResult === "array") {
|
||||
return {
|
||||
valid: true,
|
||||
result: showResult,
|
||||
}
|
||||
}
|
||||
if (typeof showResult === "object" || typeof showResult === "array") {
|
||||
return {
|
||||
valid: true,
|
||||
result: showResult,
|
||||
}
|
||||
}
|
||||
|
||||
if (showResult[0] === "\"") {
|
||||
return {
|
||||
valid: false,
|
||||
result: showResult,
|
||||
}
|
||||
}
|
||||
if (showResult[0] === "\"") {
|
||||
return {
|
||||
valid: false,
|
||||
result: showResult,
|
||||
}
|
||||
}
|
||||
|
||||
var jsonvalid = true
|
||||
try {
|
||||
if (!showResult.includes("{") && !showResult.includes("[")) {
|
||||
jsonvalid = false
|
||||
|
||||
return {
|
||||
valid: jsonvalid,
|
||||
result: showResult,
|
||||
};
|
||||
return {
|
||||
valid: jsonvalid,
|
||||
result: showResult,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -505,102 +509,94 @@ export const validateJson = (showResult) => {
|
||||
|
||||
var result = showResult;
|
||||
try {
|
||||
result = jsonvalid ? JSON.parse(showResult, { "storeAsString": true }) : showResult;
|
||||
result = jsonvalid ? JSON.parse(showResult, {"storeAsString": true}) : showResult;
|
||||
} catch (e) {
|
||||
////console.log("Failed parsing JSON even though its valid: ", e)
|
||||
jsonvalid = false;
|
||||
}
|
||||
|
||||
if (jsonvalid === false) {
|
||||
if (jsonvalid === false) {
|
||||
|
||||
if (typeof showResult === 'string') {
|
||||
showResult = showResult.trim()
|
||||
}
|
||||
|
||||
try {
|
||||
var newstr = showResult.replaceAll("'", '"')
|
||||
|
||||
// Basic workarounds for issues with Python Dicts -> JSON
|
||||
if (newstr.includes(": None")) {
|
||||
newstr = newstr.replaceAll(": None", ': null')
|
||||
}
|
||||
|
||||
if (newstr.includes("[\"{") && newstr.includes("}\"]")) {
|
||||
newstr = newstr.replaceAll("[\"{", '[{')
|
||||
newstr = newstr.replaceAll("}\"]", '}]')
|
||||
}
|
||||
|
||||
if (newstr.includes("{\"[") && newstr.includes("]\"}")) {
|
||||
newstr = newstr.replaceAll("{\"[", '[{')
|
||||
newstr = newstr.replaceAll("]\"}", '}]')
|
||||
}
|
||||
|
||||
result = JSON.parse(newstr)
|
||||
jsonvalid = true
|
||||
} catch (e) {
|
||||
|
||||
//console.log("Failed parsing JSON even though its valid (2): ", e)
|
||||
jsonvalid = false
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonvalid && typeof result === "number") {
|
||||
jsonvalid = false
|
||||
}
|
||||
|
||||
// This is where we start recursing
|
||||
if (jsonvalid) {
|
||||
// Check fields if they can be parsed too
|
||||
try {
|
||||
for (const [key, value] of Object.entries(result)) {
|
||||
if (typeof value === "string") {
|
||||
value = value.replaceAll(" ", "_")
|
||||
if (typeof showResult === 'string') {
|
||||
showResult = showResult.trim()
|
||||
}
|
||||
|
||||
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
||||
//console.log("CHECKING STRING: ", value)
|
||||
try {
|
||||
var newstr = showResult.replaceAll("'", '"')
|
||||
|
||||
const inside_result = validateJson(value)
|
||||
if (inside_result.valid) {
|
||||
//console.log("INSIDE RESULT: ", inside_result.result)
|
||||
// Basic workarounds for issues with Python Dicts -> JSON
|
||||
if (newstr.includes(": None")) {
|
||||
newstr = newstr.replaceAll(": None", ': null')
|
||||
}
|
||||
|
||||
if (typeof inside_result.result === "string") {
|
||||
const newres = JSON.parse(inside_result.result)
|
||||
if (newstr.includes("[\"{") && newstr.includes("}\"]")) {
|
||||
newstr = newstr.replaceAll("[\"{", '[{')
|
||||
newstr = newstr.replaceAll("}\"]", '}]')
|
||||
}
|
||||
|
||||
result[key] = newres
|
||||
} else {
|
||||
result[key] = inside_result.result
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (newstr.includes("{\"[") && newstr.includes("]\"}")) {
|
||||
newstr = newstr.replaceAll("{\"[", '[{')
|
||||
newstr = newstr.replaceAll("]\"}", '}]')
|
||||
}
|
||||
|
||||
// Usually only reaches here if raw array > dict > value
|
||||
if (typeof showResult !== "array") {
|
||||
for (const [subkey, subvalue] of Object.entries(value)) {
|
||||
if (typeof subvalue === "string") {
|
||||
subvalue = subvalue.replaceAll(" ", "_")
|
||||
}
|
||||
result = JSON.parse(newstr)
|
||||
jsonvalid = true
|
||||
} catch (e) {
|
||||
|
||||
if (typeof subvalue === "string" && (subvalue.startsWith("{") || subvalue.startsWith("["))) {
|
||||
const inside_result = validateJson(subvalue)
|
||||
if (inside_result.valid) {
|
||||
if (typeof inside_result.result === "string") {
|
||||
const newres = JSON.parse(inside_result.result)
|
||||
result[key][subkey] = newres
|
||||
} else {
|
||||
result[key][subkey] = inside_result.result
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log("Failed parsing JSON even though its valid (2): ", e)
|
||||
jsonvalid = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//console.log("Failed parsing inside json subvalues: ", e)
|
||||
}
|
||||
}
|
||||
if (jsonvalid && typeof result === "number") {
|
||||
jsonvalid = false
|
||||
}
|
||||
|
||||
// This is where we start recursing
|
||||
if (jsonvalid) {
|
||||
// Check fields if they can be parsed too
|
||||
try {
|
||||
for (const [key, value] of Object.entries(result)) {
|
||||
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
||||
//console.log("CHECKING STRING: ", value)
|
||||
|
||||
const inside_result = validateJson(value)
|
||||
if (inside_result.valid) {
|
||||
//console.log("INSIDE RESULT: ", inside_result.result)
|
||||
|
||||
if (typeof inside_result.result === "string") {
|
||||
const newres = JSON.parse(inside_result.result)
|
||||
|
||||
result[key] = newres
|
||||
} else {
|
||||
result[key] = inside_result.result
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Usually only reaches here if raw array > dict > value
|
||||
if (typeof showResult !== "array") {
|
||||
for (const [subkey, subvalue] of Object.entries(value)) {
|
||||
if (typeof subvalue === "string" && (subvalue.startsWith("{") || subvalue.startsWith("["))) {
|
||||
const inside_result = validateJson(subvalue)
|
||||
if (inside_result.valid) {
|
||||
if (typeof inside_result.result === "string") {
|
||||
const newres = JSON.parse(inside_result.result)
|
||||
result[key][subkey] = newres
|
||||
} else {
|
||||
result[key][subkey] = inside_result.result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//console.log("Failed parsing inside json subvalues: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: jsonvalid,
|
||||
@@ -608,6 +604,7 @@ export const validateJson = (showResult) => {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//Custom hook for handling styling of the dropzone
|
||||
const useDropzoneStyles = () => {
|
||||
const { leftSideBarOpenByClick } = useContext(Context);
|
||||
|
||||
Reference in New Issue
Block a user