MSSP multi tenant workflow features ayy
This commit is contained in:
@@ -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,
|
||||
}}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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={{
|
||||
|
||||
@@ -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"]);
|
||||
|
||||
@@ -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`}
|
||||
|
||||
Reference in New Issue
Block a user