Started backend app search engine
This commit is contained in:
@@ -5743,15 +5743,16 @@ func init() {
|
|||||||
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
|
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
|
||||||
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
|
// App specific
|
||||||
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
r.HandleFunc("/api/v1/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{appId}", deleteWorkflowApp).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{appId}", deleteWorkflowApp).Methods("DELETE", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/{appId}/config", getWorkflowAppConfig).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/{appId}/config", getWorkflowAppConfig).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps", getWorkflowApps).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps", getWorkflowApps).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps", setNewWorkflowApp).Methods("PUT", "OPTIONS")
|
r.HandleFunc("/api/v1/apps", setNewWorkflowApp).Methods("PUT", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/apps/search", getSpecificApps).Methods("POST", "OPTIONS")
|
||||||
|
|
||||||
// Legacy things
|
// Legacy app things
|
||||||
r.HandleFunc("/api/v1/workflows/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows/apps", getWorkflowApps).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/apps", getWorkflowApps).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows/apps", setNewWorkflowApp).Methods("PUT", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/apps", setNewWorkflowApp).Methods("PUT", "OPTIONS")
|
||||||
|
|||||||
@@ -2917,6 +2917,51 @@ func handleGetfile(resp http.ResponseWriter, request *http.Request) ([]byte, err
|
|||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSpecificApps(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
cors := handleCors(resp, request)
|
||||||
|
if cors {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just need to be logged in
|
||||||
|
// FIXME - should have some permissions?
|
||||||
|
_, err := handleApiAuthentication(resp, request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in set new app: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error with body read: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type tmpStruct struct {
|
||||||
|
Search string `json:"search"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmpBody tmpStruct
|
||||||
|
err = json.Unmarshal(body, &tmpBody)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error with unmarshal tmpBody: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME - continue the search here with github repos etc.
|
||||||
|
// Caching might be smart :D
|
||||||
|
log.Printf("Body: %s", string(body))
|
||||||
|
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
||||||
|
}
|
||||||
|
|
||||||
func validateAppInput(resp http.ResponseWriter, request *http.Request) {
|
func validateAppInput(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ const AngularWorkflow = (props) => {
|
|||||||
const [cystyle, ] = useState(cytoscapestyle)
|
const [cystyle, ] = useState(cytoscapestyle)
|
||||||
const [cy, setCy] = React.useState()
|
const [cy, setCy] = React.useState()
|
||||||
|
|
||||||
|
const [appSearch, setAppSearch] = React.useState("")
|
||||||
const [currentView, setCurrentView] = React.useState("apps")
|
const [currentView, setCurrentView] = React.useState("apps")
|
||||||
const [, setAppSearchValue] = React.useState("")
|
|
||||||
const [triggerAuthentication, setTriggerAuthentication] = React.useState({})
|
const [triggerAuthentication, setTriggerAuthentication] = React.useState({})
|
||||||
const [triggerFolders, setTriggerFolders] = React.useState([])
|
const [triggerFolders, setTriggerFolders] = React.useState([])
|
||||||
|
|
||||||
@@ -1385,10 +1385,6 @@ const AngularWorkflow = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const setAppSearch = (event) => {
|
|
||||||
setFilteredApps(apps.filter(app => app.name.includes(event.target.value)))
|
|
||||||
}
|
|
||||||
|
|
||||||
const appViewStyle = {
|
const appViewStyle = {
|
||||||
marginLeft: "5px",
|
marginLeft: "5px",
|
||||||
marginRight: "5px",
|
marginRight: "5px",
|
||||||
@@ -1568,6 +1564,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const HandleLeftView = () => {
|
const HandleLeftView = () => {
|
||||||
|
// Defaults to apps.
|
||||||
var thisview = <AppView />
|
var thisview = <AppView />
|
||||||
if (currentView === "triggers") {
|
if (currentView === "triggers") {
|
||||||
thisview = <TriggersView />
|
thisview = <TriggersView />
|
||||||
@@ -1577,14 +1574,6 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
<div style={{cursor: "pointer", height: 20, marginLeft: 10, marginTop: 10}} onClick={() => {
|
|
||||||
setLeftViewOpen(false)
|
|
||||||
setLeftBarSize(50)
|
|
||||||
}}>
|
|
||||||
<Tooltip color="primary" title="Minimize" placement="top">
|
|
||||||
<KeyboardArrowLeftIcon />
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<Divider style={{marginTop: 10, height: 1, width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
|
<Divider style={{marginTop: 10, height: 1, width: "100%", backgroundColor: "rgb(91, 96, 100)"}}/>
|
||||||
<div style={{minHeight: bodyHeight-appBarSize-150, maxHeight: bodyHeight-appBarSize-100}}>
|
<div style={{minHeight: bodyHeight-appBarSize-150, maxHeight: bodyHeight-appBarSize-100}}>
|
||||||
{thisview}
|
{thisview}
|
||||||
@@ -1981,11 +1970,36 @@ const AngularWorkflow = (props) => {
|
|||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const runAppSearch = (event) => {
|
||||||
|
setAppSearch(event.target.value)
|
||||||
|
setFilteredApps(apps.filter(app => app.name.toLowerCase().includes(event.target.value.trim().toLowerCase())))
|
||||||
|
}
|
||||||
|
|
||||||
const AppView = () => {
|
const AppView = () => {
|
||||||
return(
|
return(
|
||||||
<div style={appViewStyle}>
|
<div style={appViewStyle}>
|
||||||
<div style={{flex: "1"}}>
|
<div style={{flex: "1"}}>
|
||||||
<div style={appScrollStyle}>
|
<div style={appScrollStyle}>
|
||||||
|
{/*
|
||||||
|
<TextField
|
||||||
|
style={{backgroundColor: inputColor}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
color: "white",
|
||||||
|
minHeight: "50px",
|
||||||
|
marginLeft: "5px",
|
||||||
|
maxWidth: "95%",
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
color="primary"
|
||||||
|
placeholder={"Search apps"}
|
||||||
|
onChange={(event) => {
|
||||||
|
runAppSearch(event)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
*/}
|
||||||
{filteredApps.map(app=> {
|
{filteredApps.map(app=> {
|
||||||
// FIXME - add label to apps, as this might be slow with A LOT of apps
|
// FIXME - add label to apps, as this might be slow with A LOT of apps
|
||||||
var newAppname = app.name
|
var newAppname = app.name
|
||||||
|
|||||||
+38
-29
@@ -38,6 +38,7 @@ const Apps = (props) => {
|
|||||||
const [filteredApps, setFilteredApps] = React.useState([])
|
const [filteredApps, setFilteredApps] = React.useState([])
|
||||||
const [validation, setValidation] = React.useState(false)
|
const [validation, setValidation] = React.useState(false)
|
||||||
const [isLoading, setIsLoading] = React.useState(false)
|
const [isLoading, setIsLoading] = React.useState(false)
|
||||||
|
const [appSearchLoading, setAppSearchLoading] = React.useState(false)
|
||||||
|
|
||||||
const [openApi, setOpenApi] = React.useState("")
|
const [openApi, setOpenApi] = React.useState("")
|
||||||
const [openApiData, setOpenApiData] = React.useState("")
|
const [openApiData, setOpenApiData] = React.useState("")
|
||||||
@@ -109,7 +110,7 @@ const Apps = (props) => {
|
|||||||
if (responseJson.length > 0) {
|
if (responseJson.length > 0) {
|
||||||
setSelectedApp(responseJson[0])
|
setSelectedApp(responseJson[0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
alert.error(error.toString())
|
alert.error(error.toString())
|
||||||
});
|
});
|
||||||
@@ -254,33 +255,6 @@ const Apps = (props) => {
|
|||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
//const handleFile = (event) =>{
|
|
||||||
// const formData = new FormData();
|
|
||||||
// formData.append('file', event.target.files[0]);
|
|
||||||
|
|
||||||
// fetch(globalUrl+"/api/v1/workflows/apps/validate", {
|
|
||||||
// method: 'POST',
|
|
||||||
// headers: {
|
|
||||||
// 'Accept': 'application/json',
|
|
||||||
// },
|
|
||||||
// body: formData,
|
|
||||||
// credentials: "include",
|
|
||||||
// })
|
|
||||||
// .then((response) => {
|
|
||||||
// if (response.status !== 200) {
|
|
||||||
// console.log("Status not 200 for apps :O!")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// return response.json()
|
|
||||||
// })
|
|
||||||
// .then((responseJson) => {
|
|
||||||
// console.log(responseJson)
|
|
||||||
// })
|
|
||||||
// .catch(error => {
|
|
||||||
// alert.error(error.toString())
|
|
||||||
// });
|
|
||||||
//}
|
|
||||||
|
|
||||||
const UploadView = () => {
|
const UploadView = () => {
|
||||||
//var imageline = selectedApp.large_image === undefined || selectedApp.large_image.length === 0 ?
|
//var imageline = selectedApp.large_image === undefined || selectedApp.large_image.length === 0 ?
|
||||||
// <img alt="" style={{width: "80px"}} />
|
// <img alt="" style={{width: "80px"}} />
|
||||||
@@ -386,7 +360,13 @@ const Apps = (props) => {
|
|||||||
const handleSearchChange = (event) => {
|
const handleSearchChange = (event) => {
|
||||||
const searchfield = event.target.value.toLowerCase()
|
const searchfield = event.target.value.toLowerCase()
|
||||||
const newapps = apps.filter(data => data.name.toLowerCase().includes(searchfield) || data.description.toLowerCase().includes(searchfield))
|
const newapps = apps.filter(data => data.name.toLowerCase().includes(searchfield) || data.description.toLowerCase().includes(searchfield))
|
||||||
setFilteredApps(newapps)
|
|
||||||
|
if (newapps.length === 0 && !appSearchLoading) {
|
||||||
|
setAppSearchLoading(true)
|
||||||
|
runAppSearch(searchfield)
|
||||||
|
} else {
|
||||||
|
setFilteredApps(newapps)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const appView = isLoggedIn ?
|
const appView = isLoggedIn ?
|
||||||
@@ -461,6 +441,12 @@ const Apps = (props) => {
|
|||||||
<h4>
|
<h4>
|
||||||
Try a broader search term. E.g. "http" or "TheHive"
|
Try a broader search term. E.g. "http" or "TheHive"
|
||||||
</h4>
|
</h4>
|
||||||
|
<div/>
|
||||||
|
|
||||||
|
{appSearchLoading ?
|
||||||
|
<CircularProgress color="primary" style={{margin: "auto"}}/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
</Paper>
|
</Paper>
|
||||||
:
|
:
|
||||||
<Paper square style={uploadViewPaperStyle}>
|
<Paper square style={uploadViewPaperStyle}>
|
||||||
@@ -577,6 +563,29 @@ const Apps = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const runAppSearch = (searchterm) => {
|
||||||
|
const data = {"search": searchterm}
|
||||||
|
|
||||||
|
fetch(globalUrl+"/api/v1/apps/search", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
setAppSearchLoading(false)
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
console.log(responseJson)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
alert.error(error.toString())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const validateRemote = () => {
|
const validateRemote = () => {
|
||||||
setValidation(true)
|
setValidation(true)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user