Started adding optional cloud features
This commit is contained in:
+69
-7
@@ -1692,16 +1692,25 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
Expires: expiration,
|
Expires: expiration,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Migrate this to real Org
|
||||||
|
// Need to create org endpoints (create, delete etc)
|
||||||
|
currentOrg := `{
|
||||||
|
"name": "Shuffle",
|
||||||
|
"id": "123",
|
||||||
|
"role": "admin",
|
||||||
|
"cloud_sync": false
|
||||||
|
}`
|
||||||
|
|
||||||
returnData := fmt.Sprintf(`
|
returnData := fmt.Sprintf(`
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": true,
|
||||||
"admin": %s,
|
"admin": %s,
|
||||||
"tutorials": [],
|
"tutorials": [],
|
||||||
"id": "%s",
|
"id": "%s",
|
||||||
"orgs": [{"name": "Shuffle", "id": "123", "role": "admin"}],
|
"orgs": [%s],
|
||||||
"selected_org": {"name": "Shuffle", "id": "123", "role": "admin"},
|
"selected_org": %s,
|
||||||
"cookies": [{"key": "session_token", "value": "%s", "expiration": %d}]
|
"cookies": [{"key": "session_token", "value": "%s", "expiration": %d}]
|
||||||
}`, parsedAdmin, userInfo.Id, userInfo.Session, expiration.Unix())
|
}`, parsedAdmin, userInfo.Id, currentOrg, currentOrg, userInfo.Session, expiration.Unix())
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(returnData))
|
resp.Write([]byte(returnData))
|
||||||
@@ -6449,6 +6458,55 @@ func runInit(ctx context.Context) {
|
|||||||
log.Printf("Finished INIT")
|
log.Printf("Finished INIT")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
cors := handleCors(resp, request)
|
||||||
|
if cors {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := handleApiAuthentication(resp, request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in verify swagger: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Role != "admin" {
|
||||||
|
log.Printf("Not admin.")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Not admin"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed reading body"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReturnData struct {
|
||||||
|
Apikey string `datastore:"apikey"`
|
||||||
|
Organization Org `datastore:"organization"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmpData ReturnData
|
||||||
|
err = json.Unmarshal(body, &tmpData)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed unmarshalling test: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Apidata: %s", tmpData.Apikey)
|
||||||
|
// FIXME: https://docs.google.com/drawings/d/1JJebpPeEVEbmH_qsAC6zf9Noygp7PytvesrkhE19QrY/edit
|
||||||
|
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var err error
|
var err error
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -6501,9 +6559,14 @@ func init() {
|
|||||||
// Queuebuilder and Workflow streams. First is to update a stream, second to get a stream
|
// Queuebuilder and Workflow streams. First is to update a stream, second to get a stream
|
||||||
// Changed from workflows/streams to streams, as appengine was messing up
|
// Changed from workflows/streams to streams, as appengine was messing up
|
||||||
// This does not increase the API counter
|
// This does not increase the API counter
|
||||||
|
// Used by frontend
|
||||||
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")
|
||||||
|
|
||||||
|
// Used by orborus
|
||||||
|
r.HandleFunc("/api/v1/workflows/queue", handleGetWorkflowqueue).Methods("GET")
|
||||||
|
r.HandleFunc("/api/v1/workflows/queue/confirm", handleGetWorkflowqueueConfirm).Methods("POST")
|
||||||
|
|
||||||
// App specific
|
// App specific
|
||||||
r.HandleFunc("/api/v1/apps/run_hotload", handleAppHotloadRequest).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/run_hotload", handleAppHotloadRequest).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
|
||||||
@@ -6530,8 +6593,6 @@ func init() {
|
|||||||
/* Everything below here increases the counters*/
|
/* Everything below here increases the counters*/
|
||||||
r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows/queue", handleGetWorkflowqueue).Methods("GET")
|
|
||||||
r.HandleFunc("/api/v1/workflows/queue/confirm", handleGetWorkflowqueueConfirm).Methods("POST")
|
|
||||||
r.HandleFunc("/api/v1/workflows/schedules", handleGetSchedules).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/schedules", handleGetSchedules).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows/download_remote", loadSpecificWorkflows).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/download_remote", loadSpecificWorkflows).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS")
|
r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS")
|
||||||
@@ -6552,7 +6613,7 @@ func init() {
|
|||||||
r.HandleFunc("/api/v1/hooks/{key}/delete", handleDeleteHook).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/hooks/{key}/delete", handleDeleteHook).Methods("DELETE", "OPTIONS")
|
||||||
|
|
||||||
// Trigger hmm
|
// Trigger hmm
|
||||||
r.HandleFunc("/api/v1/triggers/{key}", handleGetSpecificTrigger).Methods("GET", "OPTIONS")
|
//r.HandleFunc("/api/v1/triggers/{key}", handleGetSpecificTrigger).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
r.HandleFunc("/api/v1/stats/{key}", handleGetSpecificStats).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/stats/{key}", handleGetSpecificStats).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
@@ -6563,7 +6624,8 @@ func init() {
|
|||||||
r.HandleFunc("/api/v1/validate_openapi", validateSwagger).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/validate_openapi", validateSwagger).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/get_openapi/{key}", getOpenapi).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/get_openapi/{key}", getOpenapi).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
r.HandleFunc("/api/v1/execution_cleanup", cleanupExecutions).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/cloud/setup", handleCloudSetup).Methods("POST", "OPTIONS")
|
||||||
|
//r.HandleFunc("/api/v1/execution_cleanup", cleanupExecutions).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
http.Handle("/", r)
|
http.Handle("/", r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,11 +66,14 @@ type ExecutionRequest struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Role is just used for feedback for a user
|
||||||
type Org struct {
|
type Org struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Org string `json:"org"`
|
Org string `json:"org"`
|
||||||
Users []User `json:"users"`
|
Users []User `json:"users"`
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
CloudSync bool `json:"cloud_sync"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppAuthenticationStorage struct {
|
type AppAuthenticationStorage struct {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ const App = (message, props) => {
|
|||||||
<Route exact path="/oauth2" render={props => <Oauth2 isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/oauth2" render={props => <Oauth2 isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
||||||
<Route exact path="/contact" render={props => <Contact isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/contact" render={props => <Contact isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
||||||
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
||||||
<Route exact path="/admin" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
<Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
||||||
<Route exact path="/admin/:key" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
<Route exact path="/admin/:key" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
||||||
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
||||||
<Route exact path="/AdminSetup" render={props => <AdminSetup isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/AdminSetup" render={props => <AdminSetup isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
||||||
@@ -141,7 +141,7 @@ const App = (message, props) => {
|
|||||||
<Route exact path="/apps/edit/:appid" render={props => <AppCreator isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/apps/edit/:appid" render={props => <AppCreator isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} {...props} />} />
|
||||||
<Route exact path="/schedules/:key" render={props => <EditSchedule globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/schedules/:key" render={props => <EditSchedule globalUrl={globalUrl} {...props} />} />
|
||||||
<Route exact path="/workflows" render={props => <Workflows isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} cookies={cookies} {...props} />} />
|
<Route exact path="/workflows" render={props => <Workflows isLoaded={isLoaded} isLoggedIn={isLoggedIn} globalUrl={globalUrl} cookies={cookies} {...props} />} />
|
||||||
<Route exact path="/workflows/:key" render={props => <AngularWorkflow globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} {...props} />} />
|
<Route exact path="/workflows/:key" render={props => <AngularWorkflow userdata={userdata} globalUrl={globalUrl} isLoaded={isLoaded} isLoggedIn={isLoggedIn} {...props} />} />
|
||||||
<Route exact path="/docs/:key" render={props => <Docs isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/docs/:key" render={props => <Docs isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
||||||
<Route exact path="/docs" render={props => { window.location.pathname = "/docs/about" }} />
|
<Route exact path="/docs" render={props => { window.location.pathname = "/docs/about" }} />
|
||||||
<Route exact path="/introduction" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
<Route exact path="/introduction" render={props => <Introduction isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
||||||
|
|||||||
+158
-18
@@ -36,6 +36,12 @@ const Admin = (props) => {
|
|||||||
const [firstRequest, setFirstRequest] = React.useState(true);
|
const [firstRequest, setFirstRequest] = React.useState(true);
|
||||||
const [modalUser, setModalUser] = React.useState({});
|
const [modalUser, setModalUser] = React.useState({});
|
||||||
const [modalOpen, setModalOpen] = React.useState(false);
|
const [modalOpen, setModalOpen] = React.useState(false);
|
||||||
|
|
||||||
|
const [cloudSyncModalOpen, setCloudSyncModalOpen] = React.useState(false);
|
||||||
|
const [cloudSyncApikey, setCloudSyncApikey] = React.useState("");
|
||||||
|
const [loading, setLoading] = React.useState(false);
|
||||||
|
|
||||||
|
const [selectedOrganization, setSelectedOrganization] = React.useState({});
|
||||||
const [loginInfo, setLoginInfo] = React.useState("");
|
const [loginInfo, setLoginInfo] = React.useState("");
|
||||||
const [curTab, setCurTab] = React.useState(0);
|
const [curTab, setCurTab] = React.useState(0);
|
||||||
const [users, setUsers] = React.useState([]);
|
const [users, setUsers] = React.useState([]);
|
||||||
@@ -175,6 +181,41 @@ const Admin = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const enableCloudSync = (apikey, organization) => {
|
||||||
|
const data = {
|
||||||
|
apikey: apikey,
|
||||||
|
organization: organization,
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = globalUrl + '/api/v1/cloud/setup';
|
||||||
|
fetch(url, {
|
||||||
|
mode: 'cors',
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: 'include',
|
||||||
|
crossDomain: true,
|
||||||
|
withCredentials: true,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=utf-8',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response =>
|
||||||
|
response.json().then(responseJson => {
|
||||||
|
setLoading(false)
|
||||||
|
console.log(responseJson)
|
||||||
|
if (responseJson["success"] === false) {
|
||||||
|
alert.error("Failed setting up cloud sync")
|
||||||
|
} else {
|
||||||
|
alert.success("Set up cloud sync!")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
setLoading(false)
|
||||||
|
alert.error("Err: " + error.toString())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const onPasswordChange = () => {
|
const onPasswordChange = () => {
|
||||||
const data = { "username": selectedUser.username, "newpassword": newPassword }
|
const data = { "username": selectedUser.username, "newpassword": newPassword }
|
||||||
const url = globalUrl + '/api/v1/users/passwordchange';
|
const url = globalUrl + '/api/v1/users/passwordchange';
|
||||||
@@ -713,8 +754,69 @@ const Admin = (props) => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
const cloudSyncModal =
|
||||||
|
<Dialog
|
||||||
|
open={cloudSyncModalOpen}
|
||||||
|
onClose={() => { setCloudSyncModalOpen(false) }}
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
backgroundColor: theme.palette.surfaceColor,
|
||||||
|
color: "white",
|
||||||
|
minWidth: "800px",
|
||||||
|
minHeight: "320px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTitle><span style={{ color: "white" }}>
|
||||||
|
Enable cloud features
|
||||||
|
</span></DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
What does <a href="https://shuffler.io/docs/workflows#workflow_variables" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>cloud sync</a> do?
|
||||||
|
<div style={{marginTop: 5}}/>
|
||||||
|
Cloud Apikey
|
||||||
|
<div style={{display: "flex", marginBottom: 20, }}>
|
||||||
|
<TextField
|
||||||
|
color="primary"
|
||||||
|
style={{backgroundColor: theme.palette.inputColor, marginRight: 10, }}
|
||||||
|
InputProps={{
|
||||||
|
style: {
|
||||||
|
height: "50px",
|
||||||
|
color: "white",
|
||||||
|
fontSize: "1em",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
fullWidth={true}
|
||||||
|
autoComplete="cloud apikey"
|
||||||
|
id="apikey_field"
|
||||||
|
margin="normal"
|
||||||
|
placeholder="Cloud Apikey"
|
||||||
|
variant="outlined"
|
||||||
|
onChange={(event) => {
|
||||||
|
setCloudSyncApikey(event.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button disabled={cloudSyncApikey.length === 0 || loading} variant="contained" style={{ marginLeft: 15, height: 60, margin: "auto", borderRadius: "0px" }} onClick={() => {
|
||||||
|
setLoading(true)
|
||||||
|
enableCloudSync(
|
||||||
|
cloudSyncApikey,
|
||||||
|
selectedOrganization,
|
||||||
|
)
|
||||||
|
}} color="primary">
|
||||||
|
Test sync
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
* New triggers (userinput, hotmail realtime)<div/>
|
||||||
|
* Execute in the cloud rather than onprem<div/>
|
||||||
|
* Apps can be built in the cloud<div/>
|
||||||
|
* Easily share apps and workflows<div/>
|
||||||
|
* Access to powerful cloud search
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
const modalView =
|
const modalView =
|
||||||
<Dialog modal
|
<Dialog
|
||||||
open={modalOpen}
|
open={modalOpen}
|
||||||
onClose={() => { setModalOpen(false) }}
|
onClose={() => { setModalOpen(false) }}
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
@@ -1219,6 +1321,7 @@ const Admin = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
console.log("Userdata: ", props.userdata)
|
||||||
const organizationsTab = curTab === 5 ?
|
const organizationsTab = curTab === 5 ?
|
||||||
<div>
|
<div>
|
||||||
<div style={{marginTop: 20, marginBottom: 20,}}>
|
<div style={{marginTop: 20, marginBottom: 20,}}>
|
||||||
@@ -1229,7 +1332,10 @@ const Admin = (props) => {
|
|||||||
style={{}}
|
style={{}}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => setModalOpen(true)}
|
disabled
|
||||||
|
onClick={() => {
|
||||||
|
setModalOpen(true)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Add organization
|
Add organization
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1241,28 +1347,61 @@ const Admin = (props) => {
|
|||||||
style={{minWidth: 150, maxWidth: 150}}
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
/>
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary="Orborus running (TBD)"
|
primary="id"
|
||||||
style={{minWidth: 200, maxWidth: 200}}
|
style={{minWidth: 200, maxWidth: 200}}
|
||||||
/>
|
/>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary="Actions"
|
primary="Your role"
|
||||||
style={{minWidth: 150, maxWidth: 150}}
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
<ListItemText
|
||||||
<ListItem>
|
primary="Selected"
|
||||||
<ListItemText
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
primary="Enabled"
|
/>
|
||||||
style={{minWidth: 150, maxWidth: 150}}
|
<ListItemText
|
||||||
/>
|
primary="Cloud Sync"
|
||||||
<ListItemText
|
|
||||||
primary="false"
|
|
||||||
style={{minWidth: 200, maxWidth: 200}}
|
|
||||||
/>
|
|
||||||
<ListItemText
|
|
||||||
primary=<Switch checked={false} onChange={() => {console.log("INVERT")}} />
|
|
||||||
style={{minWidth: 150, maxWidth: 150}}
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
{props.userdata !== undefined && props.userdata.orgs !== null && props.userdata.orgs !== undefined && props.userdata.orgs.length > 0 ?
|
||||||
|
<span>
|
||||||
|
{props.userdata.orgs.map((data, index) => {
|
||||||
|
const isSelected = props.userdata.selected_org === undefined ? "False" : props.userdata.selected_org.id === data.id ? "True" : "False"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem key={index}>
|
||||||
|
<ListItemText
|
||||||
|
primary={data.name}
|
||||||
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary={data.id}
|
||||||
|
style={{minWidth: 200, maxWidth: 200}}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary={data.role}
|
||||||
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary={isSelected}
|
||||||
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
|
/>
|
||||||
|
<ListItemText
|
||||||
|
primary=<Switch checked={data.cloud_sync} onChange={() => {
|
||||||
|
setCloudSyncModalOpen(true)
|
||||||
|
setSelectedOrganization(data)
|
||||||
|
console.log("INVERT CLOUD SYNC")
|
||||||
|
}} />
|
||||||
|
style={{minWidth: 150, maxWidth: 150}}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
: null
|
: null
|
||||||
@@ -1360,6 +1499,7 @@ const Admin = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{modalView}
|
{modalView}
|
||||||
|
{cloudSyncModal}
|
||||||
{editUserModal}
|
{editUserModal}
|
||||||
{editAuthenticationModal}
|
{editAuthenticationModal}
|
||||||
{data}
|
{data}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user