#165: Fixed app deletion frontend bug

This commit is contained in:
frikky
2020-10-14 11:39:06 +02:00
parent c0474d400a
commit c622788472
5 changed files with 103 additions and 33 deletions
+23 -2
View File
@@ -6811,10 +6811,31 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
return return
} }
type responseStruct struct {
Success bool `json:"success"`
Reason string `json:"reason"`
}
log.Printf("Respbody: %s", string(respBody)) log.Printf("Respbody: %s", string(respBody))
resp.WriteHeader(200) responseData := responseStruct{}
resp.Write([]byte(fmt.Sprintf(`{"success": true}`))) err = json.Unmarshal(respBody, &responseData)
if err != nil {
resp.WriteHeader(500)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed handling cloud data"`)))
return
}
if responseData.Success {
resp.WriteHeader(200)
if len(responseData.Reason) > 0 {
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "%s"}`, responseData.Reason)))
} else {
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
}
} else {
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, responseData.Reason)))
}
} }
func init() { func init() {
+28 -11
View File
@@ -66,15 +66,28 @@ type ExecutionRequest struct {
Type string `json:"type"` Type string `json:"type"`
} }
type SyncFeatures struct {
Apps SyncData `json:"apps" datastore:"apps"`
Workflows SyncData `json:"apps" datastore:"apps"`
Schedules SyncData `json:"apps" datastore:"apps"`
Autocomplete SyncData `json:"apps" datastore:"apps"`
Authentication SyncData `json:"apps" datastore:"apps"`
}
type SyncData struct {
Active bool `json:"active" datastore:"active"`
}
// Role is just used for feedback for a user // Role is just used for feedback for a user
type Org struct { type Org struct {
Name string `json:"name" datastore:"name"` Name string `json:"name" datastore:"name"`
Id string `json:"id" datastore:"id"` Id string `json:"id" datastore:"id"`
Org string `json:"org" datastore:"org"` Org string `json:"org" datastore:"org"`
Users []User `json:"users" datastore:"users"` Users []User `json:"users" datastore:"users"`
Role string `json:"role" datastore:"role"` Role string `json:"role" datastore:"role"`
Roles []string `json:"roles" datastore:"roles"` Roles []string `json:"roles" datastore:"roles"`
CloudSync bool `json:"cloud_sync" datastore:"CloudSync"` CloudSync bool `json:"cloud_sync" datastore:"CloudSync"`
SyncFeatures SyncFeatures `json:"sync_features" datastore:"sync_features"`
} }
type AppAuthenticationStorage struct { type AppAuthenticationStorage struct {
@@ -1148,8 +1161,8 @@ func JSONCheck(str string) bool {
} }
func handleExecutionStatistics(execution WorkflowExecution) { func handleExecutionStatistics(execution WorkflowExecution) {
// FIXME: CLEAN UP THE JSON THAT'S SAVED! // FIXME: CLEAN UP THE JSON THAT'S SAVED.
// https://github.com/frikky/Shuffle/issues/172
appResults := []AppExecutionExample{} appResults := []AppExecutionExample{}
for _, result := range execution.Results { for _, result := range execution.Results {
resultCheck := JSONCheck(result.Result) resultCheck := JSONCheck(result.Result)
@@ -3403,6 +3416,7 @@ func deleteAppAuthentication(resp http.ResponseWriter, request *http.Request) {
resp.Write([]byte(`{"success": true}`)) resp.Write([]byte(`{"success": true}`))
} }
// FIXME: Not suitable for cloud right now :O
func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) { func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
cors := handleCors(resp, request) cors := handleCors(resp, request)
if cors { if cors {
@@ -3443,7 +3457,7 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
// FIXME - check whether it's in use and maybe restrict again for later? // FIXME - check whether it's in use and maybe restrict again for later?
// FIXME - actually delete other than private apps too.. // FIXME - actually delete other than private apps too..
private := false private := false
if app.Downloaded { if app.Downloaded && user.Role == "admin" {
log.Printf("Deleting downloaded app (authenticated users can do this)") log.Printf("Deleting downloaded app (authenticated users can do this)")
} else if user.Id != app.Owner && user.Role != "admin" { } else if user.Id != app.Owner && user.Role != "admin" {
log.Printf("Wrong user (%s) for app %s (delete)", user.Username, app.Name) log.Printf("Wrong user (%s) for app %s (delete)", user.Username, app.Name)
@@ -3463,6 +3477,8 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
return return
} }
// Finds workflows using the app to set errors
// FIXME: this will be WAY too big for cloud :O
for _, workflow := range workflows { for _, workflow := range workflows {
found := false found := false
@@ -3483,7 +3499,8 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
workflow.Actions = newActions workflow.Actions = newActions
for _, trigger := range workflow.Triggers { for _, trigger := range workflow.Triggers {
log.Printf("TRIGGER: %#v", trigger) _ = trigger
//log.Printf("TRIGGER: %#v", trigger)
//err = deleteSchedule(ctx, scheduleId) //err = deleteSchedule(ctx, scheduleId)
//if err != nil { //if err != nil {
// if strings.Contains(err.Error(), "Job not found") { // if strings.Contains(err.Error(), "Job not found") {
+1 -2
View File
@@ -2611,7 +2611,7 @@ const AngularWorkflow = (props) => {
} }
} }
if (curstring.length > 0) { if (curstring.length > 0 && actionlist !== null) {
// Search back in the action list // Search back in the action list
curstring = curstring.split(" ").join("_").toLowerCase() curstring = curstring.split(" ").join("_").toLowerCase()
var actionItem = actionlist.find(data => data.autocomplete.split(" ").join("_").toLowerCase() === curstring) var actionItem = actionlist.find(data => data.autocomplete.split(" ").join("_").toLowerCase() === curstring)
@@ -3794,7 +3794,6 @@ const AngularWorkflow = (props) => {
// Uses the target's parents, as the target should be executing the checks (I think) // Uses the target's parents, as the target should be executing the checks (I think)
var parents = getParents(workflow.actions.find(a => a.id === selectedEdge["target"])) var parents = getParents(workflow.actions.find(a => a.id === selectedEdge["target"]))
if (parents.length > 0) { if (parents.length > 0) {
console.log(parents)
data.action_field = parents[0].label data.action_field = parents[0].label
} else { } else {
data.action_field = "" data.action_field = ""
+28 -9
View File
@@ -1079,19 +1079,29 @@ const AppCreator = (props) => {
: :
<div> <div>
{actions.map((data, index) => { {actions.map((data, index) => {
var error = <Tooltip color="secondary" title={data.errors.join("\n")} placement="bottom"> var error = data.errors.length > 0 ?
<Tooltip color="primary" title={data.errors.join("\n")} placement="bottom">
<ErrorOutline />
</Tooltip>
:
<Tooltip color="secondary" title={data.errors.join("\n")} placement="bottom">
<CheckCircleIcon /> <CheckCircleIcon />
</Tooltip> </Tooltip>
// "ERROR: "+data.errors.join("\n") var bgColor = "#61afee"
if (data.errors.length > 0) { if (data.method === "POST") {
error = bgColor = "#49cc90"
<Tooltip color="primary" title={data.errors.join("\n")} placement="bottom"> } else if (data.method === "PUT") {
<ErrorOutline /> bgColor = "#fca130"
</Tooltip> } else if (data.method === "PATCH") {
bgColor = "#50e3c2"
} else if (data.method === "DELETE") {
bgColor = "#f93e3e"
} else if (data.method === "HEAD") {
bgColor = "#9012fe"
} }
const url = data.url const url = data.url
return ( return (
<Paper style={actionListStyle}> <Paper style={actionListStyle}>
@@ -1104,7 +1114,16 @@ const AppCreator = (props) => {
setUrlPath(data.url) setUrlPath(data.url)
setActionsModalOpen(true) setActionsModalOpen(true)
}}> }}>
{data.method} - {url} - {data.name} <div style={{display: "flex"}}>
<Chip
style={{backgroundColor: bgColor, color: "white", borderRadius: 5, minWidth: 80, marginRight: 10, marginTop: 2, cursor: "pointer", fontSize: 14,}}
label={data.method}
variant="contained"
/>
<span style={{fontSize: 16, marginTop: "auto", marginBottom: "auto",}}>
{url} - {data.name}
</span>
</div>
</div> </div>
</Tooltip> </Tooltip>
{/* {/*
+23 -9
View File
@@ -183,6 +183,8 @@ const Apps = (props) => {
maxHeight: 130, maxHeight: 130,
minWidth: "100%", minWidth: "100%",
maxWidth: "100%", maxWidth: "100%",
marginBottom: 5,
borderRadius: 5,
color: "white", color: "white",
backgroundColor: surfaceColor, backgroundColor: surfaceColor,
cursor: "pointer", cursor: "pointer",
@@ -295,6 +297,10 @@ const Apps = (props) => {
boxColor = "green" boxColor = "green"
} }
if (!data.activated && data.generated) {
boxColor = "orange"
}
var imageline = data.large_image.length === 0 ? var imageline = data.large_image.length === 0 ?
<img alt={data.title} style={{width: 100, height: 100}} /> <img alt={data.title} style={{width: 100, height: 100}} />
: :
@@ -325,6 +331,7 @@ const Apps = (props) => {
description = data.description.slice(0, maxDescLen)+"..." description = data.description.slice(0, maxDescLen)+"..."
} }
const version = data.app_version
return ( return (
<Paper square key={data.id} style={paperAppStyle} onClick={() => { <Paper square key={data.id} style={paperAppStyle} onClick={() => {
if (selectedApp.id !== data.id) { if (selectedApp.id !== data.id) {
@@ -337,7 +344,6 @@ const Apps = (props) => {
setSelectedAction({}) setSelectedAction({})
} }
console.log("Sharing: ", data.sharing_config)
if (data.sharing) { if (data.sharing) {
setSharingConfiguration("everyone") setSharingConfiguration("everyone")
} }
@@ -393,9 +399,10 @@ const Apps = (props) => {
const dividerColor = "rgb(225, 228, 232)" const dividerColor = "rgb(225, 228, 232)"
const uploadViewPaperStyle = { const uploadViewPaperStyle = {
minWidth: "100%", minWidth: 662.5,
maxWidth: 662.5, maxWidth: 662.5,
color: "white", color: "white",
borderRadius: 5,
backgroundColor: surfaceColor, backgroundColor: surfaceColor,
display: "flex", display: "flex",
marginBottom: 10, marginBottom: 10,
@@ -448,7 +455,7 @@ const Apps = (props) => {
</Tooltip> </Tooltip>
</Link> : null </Link> : null
var activateButton = selectedApp.generated && !selectedApp.activated ? const activateButton = selectedApp.generated && !selectedApp.activated ?
<div> <div>
<Link to={activateUrl} style={{textDecoration: "none"}}> <Link to={activateUrl} style={{textDecoration: "none"}}>
<Button <Button
@@ -476,7 +483,12 @@ const Apps = (props) => {
</div> </div>
: null : null
var deleteButton = ((selectedApp.private_id !== undefined && selectedApp.private_id.length > 0 && selectedApp.generated) || (selectedApp.downloaded != undefined && selectedApp.downloaded == true)) && activateButton === null ? const deleteButton = (
(selectedApp.private_id !== undefined && selectedApp.private_id.length > 0 && selectedApp.generated)
|| (selectedApp.downloaded !== undefined && selectedApp.downloaded == true)
|| (!selectedApp.generated)
)
&& activateButton === null ?
<Tooltip title={"Delete app"}> <Tooltip title={"Delete app"}>
<Button <Button
variant="outlined" variant="outlined"
@@ -525,10 +537,10 @@ const Apps = (props) => {
return ( return (
<div> <div>
{paths.map(data => { {paths.map((data, index) => {
const circleSize = 10 const circleSize = 10
return ( return (
<MenuItem style={{backgroundColor: inputColor, color: "white"}} value={data} onClick={() => console.log(data.autocomplete)}> <MenuItem key={index} style={{backgroundColor: inputColor, color: "white"}} value={data} onClick={() => console.log(data.autocomplete)}>
{data.name} {data.name}
</MenuItem> </MenuItem>
) )
@@ -567,12 +579,13 @@ const Apps = (props) => {
{imageline} {imageline}
</div> </div>
<div style={{maxWidth: "75%", overflow: "hidden"}}> <div style={{maxWidth: "75%", overflow: "hidden"}}>
<h2>{newAppname}</h2> <h2 style={{marginTop: 20, marginBottom: 0, }}>{newAppname}</h2>
<p>{description}</p> <p style={{marginTop: 5, marginBottom: 0,}}>Version {selectedApp.app_version}</p>
<p style={{marginTop: 5, marginBottom: 0}}>{description}</p>
</div> </div>
</div> </div>
{activateButton} {activateButton}
{props.userdata.role === "admin" || props.userdata.id === selectedApp.owner ? {(props.userdata.role === "admin" || props.userdata.id === selectedApp.owner) || !selectedApp.generated ?
<div> <div>
{downloadButton} {downloadButton}
{editButton} {editButton}
@@ -957,6 +970,7 @@ const Apps = (props) => {
setIsLoading(false) setIsLoading(false)
if (response.status === 200) { if (response.status === 200) {
alert.success("Hotloaded apps!") alert.success("Hotloaded apps!")
getApps()
} }
return response.json() return response.json()