#44: Added error check when deleting an app
This commit is contained in:
@@ -1182,7 +1182,6 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
//Actions []Action `json:"actions" datastore:"actions,noindex"`
|
//Actions []Action `json:"actions" datastore:"actions,noindex"`
|
||||||
|
|
||||||
log.Printf("Hello")
|
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed hook unmarshaling: %s", err)
|
log.Printf("Failed hook unmarshaling: %s", err)
|
||||||
@@ -1191,7 +1190,6 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Hello2")
|
|
||||||
var workflow Workflow
|
var workflow Workflow
|
||||||
err = json.Unmarshal([]byte(body), &workflow)
|
err = json.Unmarshal([]byte(body), &workflow)
|
||||||
//log.Printf(string(body))
|
//log.Printf(string(body))
|
||||||
@@ -1216,12 +1214,23 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
log.Println("Pre")
|
log.Println("Pre")
|
||||||
for _, action := range workflow.Actions {
|
for _, action := range workflow.Actions {
|
||||||
allNodes = append(allNodes, action.ID)
|
allNodes = append(allNodes, action.ID)
|
||||||
|
|
||||||
if action.Environment == "" {
|
if action.Environment == "" {
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "An environment for %s is required"}`, action.Label)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "An environment for %s is required"}`, action.Label)))
|
||||||
return
|
return
|
||||||
action.IsValid = true
|
action.IsValid = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Have a good way of tracking errors. ID's or similar.
|
||||||
|
if !action.IsValid {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Node %s is invalid and needs to be remade."}`, action.Label)))
|
||||||
|
return
|
||||||
|
action.IsValid = true
|
||||||
|
action.Errors = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
newActions = append(newActions, action)
|
newActions = append(newActions, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2653,6 +2662,65 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
|
|||||||
private = true
|
private = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q := datastore.NewQuery("workflow")
|
||||||
|
var workflows []Workflow
|
||||||
|
_, err = dbclient.GetAll(ctx, q, &workflows)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, workflow := range workflows {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
newActions := []Action{}
|
||||||
|
for _, action := range workflow.Actions {
|
||||||
|
if action.AppName == app.Name && action.AppVersion == app.AppVersion {
|
||||||
|
found = true
|
||||||
|
action.Errors = append(action.Errors, "App has been deleted")
|
||||||
|
action.IsValid = false
|
||||||
|
}
|
||||||
|
|
||||||
|
newActions = append(newActions, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
workflow.IsValid = false
|
||||||
|
workflow.Errors = append(workflow.Errors, fmt.Sprintf("App %s_%s has been deleted", app.Name, app.AppVersion))
|
||||||
|
workflow.Actions = newActions
|
||||||
|
|
||||||
|
for _, trigger := range workflow.Triggers {
|
||||||
|
log.Printf("TRIGGER: %#v", trigger)
|
||||||
|
//err = deleteSchedule(ctx, scheduleId)
|
||||||
|
//if err != nil {
|
||||||
|
// if strings.Contains(err.Error(), "Job not found") {
|
||||||
|
// resp.WriteHeader(200)
|
||||||
|
// resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
||||||
|
// } else {
|
||||||
|
// resp.WriteHeader(401)
|
||||||
|
// resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed stopping schedule"}`)))
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = setWorkflow(ctx, workflow, workflow.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed setting workflow when deleting app: %s", err)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
log.Printf("Set %s (%s) to have errors", workflow.ID, workflow.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//resp.WriteHeader(200)
|
||||||
|
//resp.Write([]byte(`{"success": true}`))
|
||||||
|
//return
|
||||||
|
|
||||||
// Not really deleting it, just removing from user cache
|
// Not really deleting it, just removing from user cache
|
||||||
if private {
|
if private {
|
||||||
log.Printf("Deleting private app")
|
log.Printf("Deleting private app")
|
||||||
@@ -2675,6 +2743,7 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
log.Printf("Deleting public app")
|
log.Printf("Deleting public app")
|
||||||
err = DeleteKey(ctx, "workflowapp", fileId)
|
err = DeleteKey(ctx, "workflowapp", fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
frontend:
|
frontend:
|
||||||
#build: ./frontend
|
build: ./frontend
|
||||||
image: frikky/shuffle:frontend
|
image: frikky/shuffle:frontend
|
||||||
container_name: shuffle-frontend
|
container_name: shuffle-frontend
|
||||||
hostname: shuffle-frontend
|
hostname: shuffle-frontend
|
||||||
@@ -26,7 +26,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${DB_LOCATION}:/etc/shuffle
|
- ${DB_LOCATION}:/etc/shuffle
|
||||||
backend:
|
backend:
|
||||||
#build: ./backend
|
build: ./backend
|
||||||
image: frikky/shuffle:backend
|
image: frikky/shuffle:backend
|
||||||
container_name: shuffle-backend
|
container_name: shuffle-backend
|
||||||
hostname: ${BACKEND_HOSTNAME}
|
hostname: ${BACKEND_HOSTNAME}
|
||||||
|
|||||||
@@ -814,7 +814,7 @@ const AngularWorkflow = (props) => {
|
|||||||
//console.log("ACTION: ", selectedAction)
|
//console.log("ACTION: ", selectedAction)
|
||||||
//console.log("APP: ", selectedApp)
|
//console.log("APP: ", selectedApp)
|
||||||
setSelectedAction({})
|
setSelectedAction({})
|
||||||
//setSelectedApp({})
|
setSelectedApp({})
|
||||||
//setSelectedTrigger({})
|
//setSelectedTrigger({})
|
||||||
//setSelectedEdge({})
|
//setSelectedEdge({})
|
||||||
|
|
||||||
@@ -848,6 +848,7 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
const onNodeSelect = (event) => {
|
const onNodeSelect = (event) => {
|
||||||
const data = event.target.data()
|
const data = event.target.data()
|
||||||
|
console.log("NODE: ", data)
|
||||||
setLastSaved(false)
|
setLastSaved(false)
|
||||||
//console.log(data)
|
//console.log(data)
|
||||||
|
|
||||||
@@ -2564,10 +2565,16 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
const appApiView = Object.getOwnPropertyNames(selectedAction).length > 0 && Object.getOwnPropertyNames(selectedApp).length > 0 ?
|
const appApiView = Object.getOwnPropertyNames(selectedAction).length > 0 && Object.getOwnPropertyNames(selectedApp).length > 0 ?
|
||||||
<div style={appApiViewStyle}>
|
<div style={appApiViewStyle}>
|
||||||
<div style={{display: "flex", height: 40, marginBottom: 30}}>
|
<div style={{display: "flex", minHeight: 40, marginBottom: 30}}>
|
||||||
<div style={{flex: "1"}}>
|
<div style={{flex: 1}}>
|
||||||
<h3 style={{marginBottom: "5px"}}>{selectedAction.app_name}</h3>
|
<h3 style={{marginBottom: 5}}>{selectedAction.app_name}</h3>
|
||||||
<Link to="/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}}>What are apps?</Link>
|
<Link to="/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}}>What are apps?</Link>
|
||||||
|
{selectedAction.errors !== null && selectedAction.errors.length > 0 ?
|
||||||
|
<div>
|
||||||
|
Errors: {selectedAction.errors.join("\n")}
|
||||||
|
</div>
|
||||||
|
: null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{flex: "1"}}>
|
<div style={{flex: "1"}}>
|
||||||
<Button disabled={selectedAction.id === workflow.start} style={{zIndex: 5000, marginTop: "15px",}} color="primary" variant="outlined" onClick={(e) => {
|
<Button disabled={selectedAction.id === workflow.start} style={{zIndex: 5000, marginTop: "15px",}} color="primary" variant="outlined" onClick={(e) => {
|
||||||
|
|||||||
+34
-3
@@ -56,6 +56,7 @@ const Apps = (props) => {
|
|||||||
const [openApiData, setOpenApiData] = React.useState("")
|
const [openApiData, setOpenApiData] = React.useState("")
|
||||||
const [appValidation, setAppValidation] = React.useState("")
|
const [appValidation, setAppValidation] = React.useState("")
|
||||||
const [loadAppsModalOpen, setLoadAppsModalOpen] = React.useState(false);
|
const [loadAppsModalOpen, setLoadAppsModalOpen] = React.useState(false);
|
||||||
|
const [deleteModalOpen, setDeleteModalOpen] = React.useState(false);
|
||||||
const [openApiModal, setOpenApiModal] = React.useState(false);
|
const [openApiModal, setOpenApiModal] = React.useState(false);
|
||||||
const [openApiModalType, setOpenApiModalType] = React.useState("");
|
const [openApiModalType, setOpenApiModalType] = React.useState("");
|
||||||
const [openApiError, setOpenApiError] = React.useState("")
|
const [openApiError, setOpenApiError] = React.useState("")
|
||||||
@@ -352,7 +353,7 @@ const Apps = (props) => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
style={{marginLeft: 5, marginTop: 10}}
|
style={{marginLeft: 5, marginTop: 10}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteApp(selectedApp.id)
|
setDeleteModalOpen(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
@@ -819,13 +820,42 @@ const Apps = (props) => {
|
|||||||
window.location.href = "/apps/new?id="+appValidation
|
window.location.href = "/apps/new?id="+appValidation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleGithubValidation = () => {
|
const handleGithubValidation = () => {
|
||||||
getSpecificApps(openApi)
|
getSpecificApps(openApi)
|
||||||
setLoadAppsModalOpen(false)
|
setLoadAppsModalOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteModal = deleteModalOpen ?
|
||||||
|
<Dialog modal
|
||||||
|
open={deleteModalOpen}
|
||||||
|
onClose={() => {
|
||||||
|
setDeleteModalOpen(false)
|
||||||
|
}}
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
backgroundColor: surfaceColor,
|
||||||
|
color: "white",
|
||||||
|
minWidth: 500,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<div style={{textAlign: "center", color: "rgba(255,255,255,0.9)"}}>
|
||||||
|
Are you sure? <div/>Some workflows may stop working.
|
||||||
|
</div>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent style={{color: "rgba(255,255,255,0.65)", textAlign: "center"}}>
|
||||||
|
<Button style={{}} onClick={() => {deleteApp(selectedApp.id); setDeleteModalOpen(false)}} color="primary">
|
||||||
|
Yes
|
||||||
|
</Button>
|
||||||
|
<Button variant="outlined" style={{}} onClick={() => {setDeleteModalOpen(false)}} color="primary">
|
||||||
|
No
|
||||||
|
</Button>
|
||||||
|
</DialogContent>
|
||||||
|
|
||||||
|
</Dialog>
|
||||||
|
: null
|
||||||
|
|
||||||
const appsModalLoad = loadAppsModalOpen ?
|
const appsModalLoad = loadAppsModalOpen ?
|
||||||
<Dialog modal
|
<Dialog modal
|
||||||
open={loadAppsModalOpen}
|
open={loadAppsModalOpen}
|
||||||
@@ -1006,6 +1036,7 @@ const Apps = (props) => {
|
|||||||
{appView}
|
{appView}
|
||||||
{modalView}
|
{modalView}
|
||||||
{appsModalLoad}
|
{appsModalLoad}
|
||||||
|
{deleteModal}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ const data = [{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: 'node[?hasErrors]',
|
selector: "node[!is_valid]",
|
||||||
css: {
|
css: {
|
||||||
'color': '#991818',
|
'border-color': 'red',
|
||||||
'font-style': 'italic',
|
'border-width': '10px',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user