MSSP multi tenant workflow features ayy

This commit is contained in:
Frikky
2024-06-17 01:39:52 +02:00
parent fe43b683b9
commit 3f0ed868cc
14 changed files with 1064 additions and 364 deletions
+92 -58
View File
@@ -44,9 +44,9 @@ const Files = (props) => {
const { globalUrl, userdata, serverside, selectedOrganization, isCloud,isSelectedFiles } = props;
const [files, setFiles] = React.useState([]);
const [selectedNamespace, setSelectedNamespace] = React.useState("default");
const [selectedCategory, setSelectedCategory] = React.useState("default");
const [openFileId, setOpenFileId] = React.useState(false);
const [fileNamespaces, setFileNamespaces] = React.useState([]);
const [fileCategories, setFileCategories] = React.useState([]);
const [fileContent, setFileContent] = React.useState("");
const [openEditor, setOpenEditor] = React.useState(false);
const [renderTextBox, setRenderTextBox] = React.useState(false);
@@ -57,6 +57,7 @@ const Files = (props) => {
const [downloadUrl, setDownloadUrl] = React.useState("https://github.com/shuffle/standards")
const [downloadBranch, setDownloadBranch] = React.useState("main");
const [downloadFolder, setDownloadFolder] = React.useState("translation_standards");
const [contentLoading, setContentLoading] = React.useState(false)
//const alert = useAlert();
const allowedFileTypes = ["txt", "py", "yaml", "yml","json", "html", "js", "csv", "log", "eml", "msg", "md", "xml", "sh", "bat", "ps1", "psm1", "psd1", "ps1xml", "pssc", "psc1", "response"]
@@ -67,8 +68,8 @@ const Files = (props) => {
console.log('do validate')
console.log("new namespace name->",event.target.value);
fileNamespaces.push(event.target.value);
setSelectedNamespace(event.target.value);
fileCategories.push(event.target.value);
setSelectedCategory(event.target.value);
setRenderTextBox(false);
}
@@ -107,12 +108,13 @@ const Files = (props) => {
const getFiles = (namespace) => {
var parsedurl = `${globalUrl}/api/v1/files`
if (namespace === undefined || namespace === "default") {
if (namespace === undefined || namespace === null || namespace === "default") {
} else if (namespace !== undefined && namespace !== null && namespace !== "") {
parsedurl = `${globalUrl}/api/v1/files/namespaces/${namespace}?ids=true`
} else if (selectedNamespace !== undefined && selectedNamespace !== null && selectedNamespace !== "default" && selectedNamespace !== "") {
parsedurl = `${globalUrl}/api/v1/files/namespaces/${selectedNamespace}?ids=true`
} else if (selectedCategory !== undefined && selectedCategory !== null && selectedCategory !== "default" && selectedCategory !== "") {
parsedurl = `${globalUrl}/api/v1/files/namespaces/${selectedCategory}?ids=true`
}
fetch(parsedurl, {
@@ -149,9 +151,11 @@ const Files = (props) => {
setFiles([]);
}
if (responseJson.namespaces !== undefined && responseJson.namespaces !== null && (fileNamespaces.length === 0 || responseJson.namespaces.length > fileNamespaces.length)) {
setFileNamespaces(responseJson.namespaces);
}
if (namespace === undefined || namespace === null || namespace === "default") {
if (responseJson.namespaces !== undefined && responseJson.namespaces !== null && (fileCategories.length === 0 || responseJson.namespaces.length > fileCategories.length)) {
setFileCategories(responseJson.namespaces)
}
}
})
.catch((error) => {
toast(error.toString());
@@ -159,7 +163,21 @@ const Files = (props) => {
};
useEffect(() => {
getFiles(selectedNamespace)
getFiles("default")
setTimeout(() => {
var category = selectedCategory
if (window.location.search.includes("category=")) {
const urlParams = new URLSearchParams(window.location.search)
category = urlParams.get("category")
}
if (category !== undefined && category !== null && category.length > 0 && category !== "default") {
setSelectedCategory(category)
}
getFiles(category)
}, 1000)
}, []);
const importStandardsFromUrl = (url, folder) => {
@@ -393,7 +411,7 @@ const Files = (props) => {
toast("Failed to delete file: " + responseJson.reason);
}
setTimeout(() => {
getFiles();
getFiles(selectedCategory)
}, 1500);
})
.catch((error) => {
@@ -402,6 +420,8 @@ const Files = (props) => {
};
const readFileData = (file) => {
setContentLoading(true)
fetch(globalUrl + "/api/v1/files/" + file.id + "/content", {
method: "GET",
headers: {
@@ -411,6 +431,7 @@ const Files = (props) => {
credentials: "include",
})
.then((response) => {
setContentLoading(false)
if (response.status !== 200) {
console.log("Status not 200 for file :O!");
return "";
@@ -428,12 +449,12 @@ const Files = (props) => {
return respdata
})
.then((responseData) => {
setFileContent(responseData);
//console.log("filecontent state ",fileContent);
setFileContent(responseData);
//console.log("filecontent state ",fileContent);
})
.catch((error) => {
toast(error.toString());
setContentLoading(false)
toast(error.toString())
});
};
@@ -505,12 +526,12 @@ const Files = (props) => {
};
if (
selectedNamespace !== undefined &&
selectedNamespace !== null &&
selectedNamespace.length > 0 &&
selectedNamespace !== "default"
selectedCategory !== undefined &&
selectedCategory !== null &&
selectedCategory.length > 0 &&
selectedCategory !== "default"
) {
data.namespace = selectedNamespace;
data.namespace = selectedCategory;
}
fetch(globalUrl + "/api/v1/files/create", {
@@ -689,9 +710,9 @@ const Files = (props) => {
{fileNamespaces !== undefined &&
fileNamespaces !== null &&
fileNamespaces.length > 1 ? (
{fileCategories !== undefined &&
fileCategories !== null &&
fileCategories.length > 1 ? (
<FormControl style={{ minWidth: 150, maxWidth: 150 }}>
<InputLabel id="input-namespace-label">File Category</InputLabel>
<Select
@@ -703,18 +724,26 @@ const Files = (props) => {
maxWidth: 150,
float: "right",
}}
value={selectedNamespace}
value={selectedCategory}
onChange={(event) => {
setSelectedNamespace(event.target.value);
setSelectedCategory(event.target.value)
if (event.target.value === "all" || event.target.value === "default") {
getFiles()
} else {
getFiles(event.target.value)
}
// Add it to the url as a query
if (window.location.search.includes("category=")) {
const newurl = window.location.href.replace(/category=[^&]+/, `category=${event.target.value}`)
window.history.pushState({ path: newurl }, "", newurl)
} else {
window.history.pushState({ path: window.location.href }, "", `${window.location.href}&category=${event.target.value}`)
}
}}
>
{fileNamespaces.map((data, index) => {
{fileCategories.map((data, index) => {
return (
<MenuItem
key={index}
@@ -731,31 +760,31 @@ const Files = (props) => {
<div style={{display: "inline-flex", position:"relative"}}>
{renderTextBox ?
<Tooltip title={"Close"} style={{}} aria-label={""}>
<Button
style={{ marginLeft: 5, marginRight: 15 }}
color="primary"
onClick={() => {
setRenderTextBox(false);
console.log(" close clicked")
}}
>
<ClearIcon/>
</Button>
</Tooltip>
:
<Tooltip title={"Add new file category"} style={{}} aria-label={""}>
<Button
style={{ marginLeft: 5, marginRight: 15 }}
color="primary"
onClick={() => {
setRenderTextBox(true);
}}
>
<AddIcon/>
</Button>
</Tooltip> }
<Tooltip title={"Close"} style={{}} aria-label={""}>
<Button
style={{ marginLeft: 5, marginRight: 15 }}
color="primary"
onClick={() => {
setRenderTextBox(false);
console.log(" close clicked")
}}
>
<ClearIcon/>
</Button>
</Tooltip>
:
<Tooltip title={"Add new file category"} style={{}} aria-label={""}>
<Button
style={{ marginLeft: 5, marginRight: 15 }}
color="primary"
onClick={() => {
setRenderTextBox(true);
}}
>
<AddIcon/>
</Button>
</Tooltip>
}
{renderTextBox && <TextField
onKeyPress={(event)=>{
@@ -783,6 +812,7 @@ const Files = (props) => {
isFileEditor = {true}
key = {fileContent} //https://reactjs.org/docs/reconciliation.html#recursing-on-children
runUpdateText = {runUpdateText}
contentLoading = {contentLoading}
/>
{isSelectedFiles?null:
<Divider
@@ -795,15 +825,17 @@ const Files = (props) => {
<List style={{borderRadius: isSelectedFiles?8:null, border:isSelectedFiles?"1px solid #494949":null, marginTop:isSelectedFiles?24:null}}>
<ListItem style={{width:isSelectedFiles?"100%":null, borderBottom:isSelectedFiles?"1px solid #494949":null}}>
{/*
<ListItemText
primary="Updated"
style={{ maxWidth: 185, minWidth: 185 }}
/>
*/}
<ListItemText
primary="Name"
style={{
maxWidth: 150,
minWidth: 150,
maxWidth: 250,
minWidth: 250,
overflow: "hidden",
marginLeft: 10,
}}
@@ -814,7 +846,7 @@ const Files = (props) => {
/>
<ListItemText
primary="Md5"
style={{ minWidth: isSelectedFiles?210:250, maxWidth: isSelectedFiles?210:250, overflow: "hidden" }}
style={{ minWidth: isSelectedFiles ? 210:250, maxWidth: isSelectedFiles?210:250, overflow: "hidden" }}
/>
<ListItemText
primary="Status"
@@ -832,7 +864,7 @@ const Files = (props) => {
file.namespace = "default";
}
if (file.namespace !== selectedNamespace) {
if (file.namespace !== selectedCategory) {
return null;
}
@@ -853,6 +885,7 @@ const Files = (props) => {
overflow: "hidden",
}}
>
{/*
<ListItemText
style={{
maxWidth: isSelectedFiles ? 170:225,
@@ -861,10 +894,11 @@ const Files = (props) => {
}}
primary={new Date(file.updated_at * 1000).toISOString()}
/>
*/}
<ListItemText
style={{
maxWidth: 150,
minWidth: 150,
maxWidth: 250,
minWidth: 250,
overflow: "hidden",
marginLeft: 10,
}}
+2 -6
View File
@@ -546,7 +546,7 @@ const Header = (props) => {
rel="noopener noreferrer"
target="_blank"
>
<Tooltip color="primary" title={"Join the Shuffle Automation Community"} placement="left">
<Tooltip color="primary" title={"Shuffle is Open Source, and has a thriving Discord Automation Community"} placement="left">
<IconButton
color="primary"
style={{}}
@@ -554,11 +554,7 @@ const Header = (props) => {
aria-haspopup="true"
onClick={(event) => { }}
>
<img
alt="Discord Community Join"
src={"/images/social/discord.png"}
style={{ height: 30, width: 30 }}
/>
<svg viewBox="0 0 256 199" width="256" height="199" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" style={{height: 30, width: 30, }}><path d="M216.856 16.597A208.502 208.502 0 0 0 164.042 0c-2.275 4.113-4.933 9.645-6.766 14.046-19.692-2.961-39.203-2.961-58.533 0-1.832-4.4-4.55-9.933-6.846-14.046a207.809 207.809 0 0 0-52.855 16.638C5.618 67.147-3.443 116.4 1.087 164.956c22.169 16.555 43.653 26.612 64.775 33.193A161.094 161.094 0 0 0 79.735 175.3a136.413 136.413 0 0 1-21.846-10.632 108.636 108.636 0 0 0 5.356-4.237c42.122 19.702 87.89 19.702 129.51 0a131.66 131.66 0 0 0 5.355 4.237 136.07 136.07 0 0 1-21.886 10.653c4.006 8.02 8.638 15.67 13.873 22.848 21.142-6.58 42.646-16.637 64.815-33.213 5.316-56.288-9.08-105.09-38.056-148.36ZM85.474 135.095c-12.645 0-23.015-11.805-23.015-26.18s10.149-26.2 23.015-26.2c12.867 0 23.236 11.804 23.015 26.2.02 14.375-10.148 26.18-23.015 26.18Zm85.051 0c-12.645 0-23.014-11.805-23.014-26.18s10.148-26.2 23.014-26.2c12.867 0 23.236 11.804 23.015 26.2 0 14.375-10.148 26.18-23.015 26.18Z" fill="#5865F2"/></svg>
</IconButton>
</Tooltip>
</a>
+9 -7
View File
@@ -1925,7 +1925,7 @@ const ParsedAction = (props) => {
}}
/>
</Tooltip>
<Tooltip title="Autocomplete text" placement="top">
<Tooltip title="Autocomplete text" placement="bottom">
<AddCircleOutlineIcon
style={{ cursor: "pointer", margin: multiline ? 5 : 0, }}
onClick={(event) => {
@@ -3078,7 +3078,6 @@ const ParsedAction = (props) => {
selectedApp.actions.filter((a) =>
a.category_label !== undefined && a.category_label !== null && a.category_label.length > 0).concat(sortByKey(selectedApp.actions, "label"))
).sort(sortByCategoryLabel))
const selectedAppIcon = selectedAction.large_image
var baselabel = selectedAction.label
@@ -3156,9 +3155,11 @@ const ParsedAction = (props) => {
}
if (!found) {
toast("No result for this action yet. Please run the workflow first.")
toast.info("No result for this action yet. Please run the workflow first.")
}
}
} else {
toast.info("No workflow runs to search through. Run the workflow first.")
}
}}
>
<Tooltip
@@ -3823,6 +3824,7 @@ const ParsedAction = (props) => {
</div>
) : null}
{showEnvironment !== undefined && showEnvironment && environments.length > 1 && !isIntegration ? (
<div style={{ marginTop: "20px" }}>
<Typography style={{color: "rgba(255,255,255,0.7)"}}>Environment</Typography>
@@ -3831,9 +3833,9 @@ const ParsedAction = (props) => {
disableScrollLock: true,
}}
value={
selectedActionEnvironment === undefined || selectedActionEnvironment === null ||
selectedActionEnvironment.Name === undefined || selectedActionEnvironment.Name === null
? isCloud ? "Cloud" : "Shuffle"
selectedActionEnvironment === undefined || selectedActionEnvironment === null || selectedActionEnvironment.Name === undefined || selectedActionEnvironment.Name === null
?
selectedAction.environment !== undefined && selectedAction.environment !== null && selectedAction.environment.length > 0 ? selectedAction.environment : isCloud ? "Cloud" : "Shuffle"
: selectedActionEnvironment.Name
}
SelectDisplayProps={{
+18 -2
View File
@@ -27,8 +27,9 @@ const Priorities = (props) => {
const [selectedWorkflow, setSelectedWorkflow] = React.useState("NO HIGHLIGHT");
const [selectedExecutionId, setSelectedExecutionId] = React.useState("NO HIGHLIGHT");
let navigate = useNavigate();
const [highlightKMS, setHighlightKMS] = React.useState(false)
let navigate = useNavigate();
useEffect(() => {
getFramework()
@@ -36,6 +37,12 @@ const Priorities = (props) => {
const urlParams = new URLSearchParams(window.location.search)
const workflow = urlParams.get("workflow")
const execution_id = urlParams.get("execution_id")
const kms = urlParams.get("kms")
if (kms !== null && kms !== undefined && kms.length > 0 && kms === "true") {
toast.info("KMS-related notifications are highlighted.")
setHighlightKMS(true)
}
if (execution_id !== null) {
setSelectedExecutionId(execution_id)
@@ -217,7 +224,16 @@ const Priorities = (props) => {
var orgId = "";
const highlighted = selectedExecutionId === "" && selectedWorkflow === "" ? false : data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow)
var highlighted = selectedExecutionId === "" && selectedWorkflow === "" ? false : data.reference_url === undefined || data.reference_url === null || data.reference_url.length === 0 ? false : data.reference_url.includes(selectedExecutionId) || data.reference_url.includes(selectedWorkflow)
if (!highlighted && highlightKMS) {
if (data.title !== undefined && data.title !== null && data.title.toLowerCase().includes("kms")) {
highlighted = true
} else if (data.description !== undefined && data.description !== null && data.description.toLowerCase().includes("kms")) {
highlighted = true
}
}
if (userdata.orgs !== undefined) {
const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]);
+12 -2
View File
@@ -107,10 +107,9 @@ const CodeEditor = (props) => {
getParents,
fieldname,
contentLoading,
} = props
const [localcodedata, setlocalcodedata] = React.useState(codedata === undefined || codedata === null || codedata.length === 0 ? "" : codedata);
//const { setContainer } = useCodeMirror({
@@ -989,6 +988,17 @@ const CodeEditor = (props) => {
},
}}
>
{contentLoading === true ?
<Tooltip
color="primary"
title={`The File content is loading. Please wait a moment.`}
placement="top"
>
<CircularProgress style={{position: "absolute", right: 106, top: 6, }}/>
</Tooltip>
: null}
<Tooltip
color="primary"
title={`Move window`}