Fixed hybrid issues

This commit is contained in:
frikky
2020-11-15 16:28:20 +01:00
parent 8abd1584aa
commit 3f98f986e7
8 changed files with 369 additions and 152 deletions
+2 -1
View File
@@ -74,7 +74,8 @@ var baseAppPath = "/home/frikky/git/shaffuru/tmp/apps"
var baseDockerName = "frikky/shuffle" var baseDockerName = "frikky/shuffle"
//var syncUrl = "http://192.168.102.54:5002" //var syncUrl = "http://192.168.102.54:5002"
var syncUrl = "http://localhost:5002" //var syncUrl = "http://localhost:5002"
var syncUrl = "https://shuffler.io"
var dbclient *datastore.Client var dbclient *datastore.Client
+14 -9
View File
@@ -68,15 +68,19 @@ type ExecutionRequest struct {
} }
type SyncFeatures struct { type SyncFeatures struct {
Webhook SyncData `json:"webhook" datastore:"webhook"` Webhook SyncData `json:"webhook" datastore:"webhook"`
Schedule SyncData `json:"schedule" datastore:"schedule"` Schedules SyncData `json:"schedules" datastore:"schedules"`
UserInput SyncData `json:"user_input" datastore:"user_input"` UserInput SyncData `json:"user_input" datastore:"user_input"`
EmailTrigger SyncData `json:"email_trigger" datastore:"email_trigger"` SendMail SyncData `json:"send_mail" datastore:"send_mail"`
Apps SyncData `json:"apps" datastore:"apps"` SendSms SyncData `json:"send_sms" datastore:"send_sms"`
Workflows SyncData `json:"workflows" datastore:"workflows"` EmailTrigger SyncData `json:"email_trigger" datastore:"email_trigger"`
Schedules SyncData `json:"schedules" datastore:"schedules"` AppExecutions SyncData `json:"app_executions" datastore:"app_executions"`
Autocomplete SyncData `json:"autocomplete" datastore:"autocomplete"` WorkflowExecutions SyncData `json:"workflow_executions" datastore:"workflow_executions"`
Authentication SyncData `json:"authentication" datastore:"authentication"` Apps SyncData `json:"apps" datastore:"apps"`
Workflows SyncData `json:"workflows" datastore:"workflows"`
Autocomplete SyncData `json:"autocomplete" datastore:"autocomplete"`
Authentication SyncData `json:"authentication" datastore:"authentication"`
Schedule SyncData `json:"schedule" datastore:"schedule"`
} }
type SyncData struct { type SyncData struct {
@@ -1836,6 +1840,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
} }
// FIXME: This is not the right time to send them, BUT it's well served for testing. Save -> send email / sms // FIXME: This is not the right time to send them, BUT it's well served for testing. Save -> send email / sms
_ = triggerInformation
if strings.Contains(triggerType, "email") { if strings.Contains(triggerType, "email") {
if email == "test@test.com" { if email == "test@test.com" {
log.Printf("Email isn't specified during save.") log.Printf("Email isn't specified during save.")
+1 -1
View File
@@ -100,7 +100,7 @@ const App = (message, props) => {
//console.log(responseJson.success) //console.log(responseJson.success)
setUserData(responseJson) setUserData(responseJson)
setIsLoggedIn(true) setIsLoggedIn(true)
console.log("Cookies: ", cookies) //console.log("Cookies: ", cookies)
// Updating cookie every request // Updating cookie every request
for (var key in responseJson["cookies"]) { for (var key in responseJson["cookies"]) {
+8
View File
@@ -0,0 +1,8 @@
import { createBrowserHistory } from 'history';
var localExport
if (typeof window !== 'undefined') {
localExport = createBrowserHistory({forceRefresh: true});
}
export default localExport
+285 -105
View File
@@ -75,6 +75,9 @@ const Admin = (props) => {
const [users, setUsers] = React.useState([]); const [users, setUsers] = React.useState([]);
const [organizations, setOrganizations] = React.useState([]); const [organizations, setOrganizations] = React.useState([]);
const [orgSyncResponse, setOrgSyncResponse] = React.useState(""); const [orgSyncResponse, setOrgSyncResponse] = React.useState("");
const [userSettings, setUserSettings] = React.useState({});
const [orgName, setOrgName] = React.useState("");
const [orgDescription, setOrgDescription] = React.useState("");
const [environments, setEnvironments] = React.useState([]); const [environments, setEnvironments] = React.useState([]);
const [authentication, setAuthentication] = React.useState([]); const [authentication, setAuthentication] = React.useState([]);
@@ -86,6 +89,7 @@ const Admin = (props) => {
const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false) const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false)
const [showArchived, setShowArchived] = React.useState(false) const [showArchived, setShowArchived] = React.useState(false)
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
const getApps = () => { const getApps = () => {
fetch(globalUrl+"/api/v1/workflows/apps", { fetch(globalUrl+"/api/v1/workflows/apps", {
method: 'GET', method: 'GET',
@@ -275,7 +279,7 @@ const Admin = (props) => {
style={{ width: 150, height: 55, flex: 1 }} style={{ width: 150, height: 55, flex: 1 }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => handleEditOrg(selectedOrganization.name, selectedOrganization.description, selectedOrganization.id, selectedOrganization.image)} onClick={() => handleEditOrg(orgName, orgDescription, selectedOrganization.id, selectedOrganization.image)}
> >
Save Changes Save Changes
</Button> </Button>
@@ -303,7 +307,7 @@ const Admin = (props) => {
.then(response => .then(response =>
response.json().then(responseJson => { response.json().then(responseJson => {
if (responseJson["success"] === false) { if (responseJson["success"] === false) {
alert.error("Failed updating org") alert.error("Failed updating org: ", responseJson.reason)
} else { } else {
alert.success("Successfully edited org!") alert.success("Successfully edited org!")
setSelectedUserModalOpen(false) setSelectedUserModalOpen(false)
@@ -386,37 +390,44 @@ const Admin = (props) => {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) })
.then(response => .then(response => {
response.json().then(responseJson => { if (response.status === 401) {
if (responseJson["success"] === false) { }
alert.error("Failed getting org: ", responseJson.readon)
} else {
setSelectedOrganization(responseJson)
var lists = {
"active": {
"triggers": [],
"features": [],
"sync": [],
},
"inactive": {
"triggers": [],
"features": [],
"sync": [],
},
}
Object.keys(responseJson.sync_features).map(function(key, index) { return response.json()
//console.log(responseJson.sync_features[key]) })
}) .then(responseJson => {
if (responseJson["success"] === false) {
alert.error("Failed getting org: ", responseJson.readon)
if (responseJson.image !== undefined && responseJson.image !== null && responseJson.image.length > 0) { } else {
setFileBase64(responseJson.image) setSelectedOrganization(responseJson)
} var lists = {
setOrganizationFeatures(lists) "active": {
"triggers": [],
"features": [],
"sync": [],
},
"inactive": {
"triggers": [],
"features": [],
"sync": [],
},
} }
}),
)
// FIXME: Set up features
Object.keys(responseJson.sync_features).map(function(key, index) {
//console.log(responseJson.sync_features[key])
})
setOrgName(responseJson.name)
setOrgDescription(responseJson.description)
if (responseJson.image !== undefined && responseJson.image !== null && responseJson.image.length > 0) {
setFileBase64(responseJson.image)
}
setOrganizationFeatures(lists)
}
})
.catch(error => { .catch(error => {
console.log("Error getting org: ", error) console.log("Error getting org: ", error)
alert.error("Error getting current organization") alert.error("Error getting current organization")
@@ -629,7 +640,7 @@ const Admin = (props) => {
}) })
.then((responseJson) => { .then((responseJson) => {
if (responseJson.success) { if (responseJson.success) {
console.log(responseJson.data) //console.log(responseJson.data)
setAuthentication(responseJson.data) setAuthentication(responseJson.data)
} else { } else {
alert.error("Failed getting authentications") alert.error("Failed getting authentications")
@@ -715,9 +726,38 @@ const Admin = (props) => {
}); });
} }
const getSettings = () => {
fetch(globalUrl+"/api/v1/getsettings", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 when getting settings :O!")
}
return response.json()
})
.then((responseJson) => {
setUserSettings(responseJson)
})
.catch(error => {
console.log(error)
});
}
if (firstRequest) { if (firstRequest) {
setFirstRequest(false) setFirstRequest(false)
getUsers() if (!isCloud) {
getUsers()
} else {
getSettings()
}
const views = { const views = {
"organization": 0, "organization": 0,
@@ -737,7 +777,7 @@ const Admin = (props) => {
} }
if (selectedOrganization.id === undefined && userdata !== undefined && userdata.active_org !== undefined) { if (selectedOrganization.id === undefined && userdata !== undefined && userdata.active_org !== undefined) {
//setSelectedOrganization(userdata.active_org) setSelectedOrganization(userdata.active_org)
handleGetOrg(userdata.active_org.id) handleGetOrg(userdata.active_org.id)
} }
@@ -1120,8 +1160,51 @@ const Admin = (props) => {
var imageData = file.length > 0 ? file : fileBase64 var imageData = file.length > 0 ? file : fileBase64
imageData = imageData === undefined || imageData.length === 0 ? defaultImage : imageData imageData = imageData === undefined || imageData.length === 0 ? defaultImage : imageData
const cancelSubscriptions = (subscription_id) => {
console.log(selectedOrganization)
const data = {
"subscription_id": subscription_id,
"action": "cancel",
"org_id": selectedOrganization.id,
}
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
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(function(response) {
if (response.status !== 200) {
console.log("Error in response")
}
handleGetOrg(selectedOrganization.id)
return response.json();
}).then(function(responseJson) {
if (responseJson.success !== undefined && responseJson.success) {
alert.success("Successfully stopped subscription!")
} else {
alert.error("Failed stopping subscription. Please contact us.")
}
})
.catch(function(error) {
console.log("Error: ", error)
alert.error("Failed stopping subscription. Please contact us.")
})
}
const imageInfo = <img src={imageData} alt="Click to upload an image (174x174)" id="logo" style={{maxWidth: 174, maxHeight: 174, minWidth: 174, minHeight: 174, objectFit: "contain",}} /> const imageInfo = <img src={imageData} alt="Click to upload an image (174x174)" id="logo" style={{maxWidth: 174, maxHeight: 174, minWidth: 174, minHeight: 174, objectFit: "contain",}} />
const organizationView = curTab === 0 ? const organizationView = curTab === 0 && selectedOrganization.id !== undefined ?
<div> <div>
<div style={{ marginTop: 20, marginBottom: 20, }}> <div style={{ marginTop: 20, marginBottom: 20, }}>
<h2 style={{ display: "inline", }}>Organization overview</h2> <h2 style={{ display: "inline", }}>Organization overview</h2>
@@ -1130,17 +1213,18 @@ const Admin = (props) => {
</span> </span>
</div> </div>
{selectedOrganization.id === undefined ? {selectedOrganization.id === undefined ?
null : <div style={{height: 250}}/>
:
<div> <div>
<div style={{color: "white", flex: "1", display: "flex", flexDirection: "row"}}> <div style={{color: "white", flex: "1", display: "flex", flexDirection: "row"}}>
<Tooltip title="Click to edit the app's image" placement="bottom"> <Tooltip title="Click to edit the app's image - 174x174" placement="bottom">
<div style={{flex: "1", margin: "10px 25px 10px 0px", border: imageData !== undefined && imageData.length > 0 ? null : "1px solid #f85a3e", cursor: "pointer", backgroundColor: imageData !== undefined && imageData.length > 0 ? null : theme.palette.inputColor, maxWidth: 174, maxHeight: 174}} onClick={() => {upload.click()}}> <div style={{flex: "1", margin: "10px 25px 10px 0px", border: imageData !== undefined && imageData.length > 0 ? null : "1px solid #f85a3e", cursor: "pointer", backgroundColor: imageData !== undefined && imageData.length > 0 ? null : theme.palette.inputColor, maxWidth: 174, maxHeight: 174}} onClick={() => {upload.click()}}>
<input hidden type="file" ref={(ref) => upload = ref} onChange={editHeaderImage} /> <input hidden type="file" ref={(ref) => upload = ref} onChange={editHeaderImage} />
{imageInfo} {imageInfo}
</div> </div>
</Tooltip> </Tooltip>
<div style={{flex: "3", color: "white",}}> <div style={{flex: "3", color: "white",}}>
<div style={{marginTop: 8}}/> <div style={{marginTop: 8}}/>
Name Name
<TextField <TextField
required required
@@ -1151,7 +1235,7 @@ const Admin = (props) => {
id="standard-required" id="standard-required"
margin="normal" margin="normal"
variant="outlined" variant="outlined"
defaultValue={selectedOrganization.name} value={orgName}
onChange={e => { onChange={e => {
const invalid = ["#", ":", "."] const invalid = ["#", ":", "."]
for (var key in invalid) { for (var key in invalid) {
@@ -1166,8 +1250,7 @@ const Admin = (props) => {
return return
} }
selectedOrganization.name = e.target.value setOrgName(e.target.value)
setSelectedOrganization(selectedOrganization)
}} }}
color="primary" color="primary"
InputProps={{ InputProps={{
@@ -1193,10 +1276,9 @@ const Admin = (props) => {
margin="normal" margin="normal"
variant="outlined" variant="outlined"
placeholder="A description for the service" placeholder="A description for the service"
defaultValue={selectedOrganization.description} value={orgDescription}
onChange={e => { onChange={e => {
selectedOrganization.description = e.target.value setOrgDescription(e.target.value)
setSelectedOrganization(selectedOrganization)
}} }}
InputProps={{ InputProps={{
classes: { classes: {
@@ -1214,65 +1296,110 @@ const Admin = (props) => {
</div> </div>
</div> </div>
<Divider style={{ marginTop: 20, marginBottom: 20, backgroundColor: theme.palette.inputColor }} /> <Divider style={{ marginTop: 20, marginBottom: 20, backgroundColor: theme.palette.inputColor }} />
<HandlePayment /> <Typography variant="h6" style={{marginBottom: "10px", color: "white"}}>Cloud syncronization</Typography>
<Typography variant="h6" style={{marginBottom: "10px", color: "white"}}>Cloud syncronization</Typography> What does <a href="https://shuffler.io/docs/hybrid#cloud_sync" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>cloud sync</a> do? Cloud syncronization is a way of getting more out of Shuffle. Shuffle will <b>ALWAYS</b> make every option open source, but features relying on other users can't be done without a collaborative approach.
What does <a href="https://shuffler.io/docs/hybrid#cloud_sync" target="_blank" style={{textDecoration: "none", color: "#f85a3e"}}>cloud sync</a> do? Cloud syncronization is a way of getting more out of Shuffle. Shuffle will <b>ALWAYS</b> make every option open source, but features relying on other users can't be done without a collaborative approach.
<div style={{display: "flex", marginBottom: 20, }}> {isCloud ?
<TextField <div style={{marginTop: 15, display: "flex"}}>
color="primary" <div style={{flex: 1}}>
style={{backgroundColor: theme.palette.inputColor, marginRight: 10, }} <Typography style={{}}>
InputProps={{ Currently syncronizing: {selectedOrganization.cloud_sync_active === true ? "True" : "False"}
style: { </Typography>
height: "50px", {selectedOrganization.cloud_sync_active ?
color: "white", <Typography style={{}}>
fontSize: "1em", Syncronization interval: {selectedOrganization.sync_config.interval === 0 ? "60" : selectedOrganization.sync_config.interval}
}, </Typography>
}} :
required null
fullWidth={true}
disabled={selectedOrganization.cloud_sync}
autoComplete="cloud apikey"
id="apikey_field"
margin="normal"
placeholder="Cloud Apikey"
variant="outlined"
onChange={(event) => {
setCloudSyncApikey(event.target.value)
}}
/>
<Button disabled={(!selectedOrganization.cloud_sync && cloudSyncApikey.length === 0) || loading} variant="contained" style={{marginTop: 15, height: 50, width: 150,}} onClick={() => {
setLoading(true)
enableCloudSync(
cloudSyncApikey,
selectedOrganization,
selectedOrganization.cloud_sync,
)
}} color="primary">
{selectedOrganization.cloud_sync ?
"Stop sync"
:
"Start sync"
} }
</Button> <Typography style={{whiteSpace: "nowrap", marginTop: 25, marginRight: 10}}>
Your Apikey
</Typography>
<TextField
color="primary"
style={{backgroundColor: theme.palette.inputColor, }}
InputProps={{
style: {
height: "50px",
color: "white",
fontSize: "1em",
},
}}
required
fullWidth={true}
disabled={true}
autoComplete="cloud apikey"
id="apikey_field"
margin="normal"
placeholder="Cloud Apikey"
variant="outlined"
defaultValue={userSettings.apikey}
/>
</div>
</div> </div>
{orgSyncResponse.length > 0 ? :
<Typography style={{marginTop: 5, marginBottom: 10}}> <div>
Error from Shuffle: {orgSyncResponse} <div style={{display: "flex", marginBottom: 20, }}>
</Typography> <TextField
: null color="primary"
} style={{backgroundColor: theme.palette.inputColor, marginRight: 10, }}
{/* InputProps={{
<Grid container style={{width: "100%", marginBottom: 15, }}> style: {
{syncList.map((data, index) => { height: "50px",
return ( color: "white",
<GridItem key={index} data={data} /> fontSize: "1em",
) },
})} }}
</Grid> required
*/} fullWidth={true}
<Typography style={{marginTop: 40}}>Cloud sync features</Typography> disabled={selectedOrganization.cloud_sync}
autoComplete="cloud apikey"
id="apikey_field"
margin="normal"
placeholder="Cloud Apikey"
variant="outlined"
onChange={(event) => {
setCloudSyncApikey(event.target.value)
}}
/>
<Button disabled={(!selectedOrganization.cloud_sync && cloudSyncApikey.length === 0) || loading} variant="contained" style={{marginTop: 15, height: 50, width: 150,}} onClick={() => {
setLoading(true)
enableCloudSync(
cloudSyncApikey,
selectedOrganization,
selectedOrganization.cloud_sync,
)
}} color="primary">
{selectedOrganization.cloud_sync ?
"Stop sync"
:
"Start sync"
}
</Button>
</div>
{orgSyncResponse.length > 0 ?
<Typography style={{marginTop: 5, marginBottom: 10}}>
Error from Shuffle: {orgSyncResponse}
</Typography>
: null
}
{/*
<Grid container style={{width: "100%", marginBottom: 15, }}>
{syncList.map((data, index) => {
return (
<GridItem key={index} data={data} />
)
})}
</Grid>
*/}
</div>
}
<Typography style={{marginTop: 40, marginLeft: 10, marginBottom: 5,}}>Cloud sync features</Typography>
<Grid container style={{width: "100%", marginBottom: 15, }}> <Grid container style={{width: "100%", marginBottom: 15, }}>
{Object.keys(selectedOrganization.sync_features).map(function(key, index) { {Object.keys(selectedOrganization.sync_features).map(function(key, index) {
if (key === "schedule") {
return null
}
//<GridItem key={index} data={data} /> //<GridItem key={index} data={data} />
const item = selectedOrganization.sync_features[key] const item = selectedOrganization.sync_features[key]
@@ -1290,8 +1417,51 @@ const Admin = (props) => {
) )
})} })}
</Grid> </Grid>
<Divider style={{ marginTop: 20, marginBottom: 20, backgroundColor: theme.palette.inputColor }} />
{isCloud && selectedOrganization.subscriptions !== null && selectedOrganization.subscriptions.length > 0 ?
<div style={{marginTop: 30, marginBottom: 20}}>
<Typography style={{marginTop: 40, marginLeft: 10, marginBottom: 5,}}>
Your subscription{selectedOrganization.subscriptions.length > 1 ? "s" : ""}
</Typography>
<Grid container spacing={3} style={{marginTop: 15}}>
{selectedOrganization.subscriptions.reverse().map((sub, index) => {
return (
<Grid item key={index} xs={4}>
<Card elevation={6} style={{backgroundColor: theme.palette.inputColor, color: "white", padding: 25, textAlign: "left",}}>
<b>Type</b>: {sub.level}<div/>
<b>Recurrence</b>: {sub.recurrence}<div/>
{sub.active ?
<div>
<b>Started</b>: {new Date(sub.startdate*1000).toISOString()}<div/>
<Button variant="outlined" color="primary" style={{marginTop: 15}} onClick={() => {
cancelSubscriptions(sub.reference)
}}>
Cancel subscription
</Button>
</div>
:
<div>
<b>Cancelled</b>: {new Date(sub.cancellationdate*1000).toISOString()}<div/>
<Typography color="textSecondary">
<b>Status</b>: Deactivated
</Typography>
</div>
}
</Card>
</Grid>
)
})}
</Grid>
<Divider style={{ marginTop: 20, backgroundColor: theme.palette.inputColor }} />
</div>
: null
}
</div> </div>
} }
<div style={{backgroundColor: "#1f2023", paddingTop: 25,}}>
<HandlePayment stripeKey={props.stripeKey} userdata={userdata} globalUrl={globalUrl} {...props} />
</div>
</div> </div>
: null : null
@@ -1508,7 +1678,11 @@ const Admin = (props) => {
<List> <List>
<ListItem> <ListItem>
<ListItemText <ListItemText
primary="Interval (seconds)" primary="Interval"
style={{maxWidth: 200}}
/>
<ListItemText
primary="Environment"
style={{maxWidth: 200}} style={{maxWidth: 200}}
/> />
<ListItemText <ListItemText
@@ -1526,6 +1700,10 @@ const Admin = (props) => {
style={{maxWidth: 200}} style={{maxWidth: 200}}
primary={schedule.seconds} primary={schedule.seconds}
/> />
<ListItemText
style={{maxWidth: 200}}
primary={schedule.environment}
/>
<ListItemText <ListItemText
primary={schedule.argument} primary={schedule.argument}
style={{maxWidth: 400, overflow: "hidden"}} style={{maxWidth: 400, overflow: "hidden"}}
@@ -1933,7 +2111,9 @@ const Admin = (props) => {
// primary={environment.Registered ? "true" : "false"} // primary={environment.Registered ? "true" : "false"}
const setConfig = (event, newValue) => { const setConfig = (event, newValue) => {
if (newValue === 2) { if (newValue === 1) {
getUsers()
} else if (newValue === 2) {
getAppAuthentication() getAppAuthentication()
} else if (newValue === 3) { } else if (newValue === 3) {
getEnvironments() getEnvironments()
@@ -1980,10 +2160,10 @@ const Admin = (props) => {
aria-label="disabled tabs example" aria-label="disabled tabs example"
> >
<Tab label=<span><BusinessIcon style={iconStyle} /> Organization</span>/> <Tab label=<span><BusinessIcon style={iconStyle} /> Organization</span>/>
<Tab label=<span><AccessibilityNewIcon style={iconStyle} />Users</span> /> {isCloud ? null : <Tab label=<span><AccessibilityNewIcon style={iconStyle} />Users</span> />}
<Tab label=<span><LockIcon style={iconStyle} />App Authentication</span>/> {isCloud ? null : <Tab label=<span><LockIcon style={iconStyle} />App Authentication</span>/>}
<Tab label=<span><EcoIcon style={iconStyle} />Environments</span>/> {isCloud ? null : <Tab label=<span><EcoIcon style={iconStyle} />Environments</span>/>}
<Tab label=<span><ScheduleIcon style={iconStyle} />Schedules</span> /> {isCloud ? null : <Tab label=<span><ScheduleIcon style={iconStyle} />Schedules</span> />}
{window.location.protocol == "http:" && window.location.port === "3000" ? <Tab label=<span><CloudIcon style={iconStyle} /> Hybrid</span>/> : null} {window.location.protocol == "http:" && window.location.port === "3000" ? <Tab label=<span><CloudIcon style={iconStyle} /> Hybrid</span>/> : null}
{window.location.protocol == "http:" && window.location.port === "3000" ? <Tab label=<span><BusinessIcon style={iconStyle} /> Organizations</span>/> : null} {window.location.protocol == "http:" && window.location.port === "3000" ? <Tab label=<span><BusinessIcon style={iconStyle} /> Organizations</span>/> : null}
{window.location.protocol === "http:" && window.location.port === "3000" ? <Tab label=<span><LockIcon style={iconStyle} />Categories</span>/> : null} {window.location.protocol === "http:" && window.location.port === "3000" ? <Tab label=<span><LockIcon style={iconStyle} />Categories</span>/> : null}
File diff suppressed because one or more lines are too long
+36 -31
View File
@@ -137,6 +137,7 @@ const Apps = (props) => {
const [isDropzone, setIsDropzone] = React.useState(false); const [isDropzone, setIsDropzone] = React.useState(false);
const upload = React.useRef(null); const upload = React.useRef(null);
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" ? true : false
const { start, stop } = useInterval({ const { start, stop } = useInterval({
duration: 5000, duration: 5000,
@@ -592,7 +593,7 @@ const Apps = (props) => {
</div> </div>
</div> </div>
{activateButton} {activateButton}
{(props.userdata.role === "admin" || props.userdata.id === selectedApp.owner) || !selectedApp.generated ? {(props.userdata !== undefined && (props.userdata.role === "admin" || props.userdata.id === selectedApp.owner) || !selectedApp.generated) ?
<div> <div>
{downloadButton} {downloadButton}
{editButton} {editButton}
@@ -618,7 +619,7 @@ const Apps = (props) => {
})} })}
</div> </div>
: null} : null}
{props.userdata.id === selectedApp.owner ? {props.userdata !== undefined && props.userdata.id === selectedApp.owner ?
<div style={{marginTop: 15}}> <div style={{marginTop: 15}}>
{/*<p><b>ID:</b> {selectedApp.id}</p>*/} {/*<p><b>ID:</b> {selectedApp.id}</p>*/}
<b style={{marginRight: 15}}>Sharing:</b> <b style={{marginRight: 15}}>Sharing:</b>
@@ -794,7 +795,7 @@ const Apps = (props) => {
} }
const uploadFile = (e) => { const uploadFile = (e) => {
const isDropzone = e.dataTransfer?.files.length > 0; const isDropzone = e.dataTransfer === undefined ? false : e.dataTransfer.files.length > 0;
const files = isDropzone ? e.dataTransfer.files : e.target.files; const files = isDropzone ? e.dataTransfer.files : e.target.files;
const reader = new FileReader(); const reader = new FileReader();
@@ -846,37 +847,41 @@ const Apps = (props) => {
</div> </div>
<Divider style={{marginBottom: 10, marginTop: 10, height: "100%", width: 1, backgroundColor: dividerColor}}/> <Divider style={{marginBottom: 10, marginTop: 10, height: "100%", width: 1, backgroundColor: dividerColor}}/>
<div style={{flex: 1, marginLeft: 10, marginRight: 10}}> <div style={{flex: 1, marginLeft: 10, marginRight: 10}}>
<div style={{display: "flex"}}> <div style={{display: "flex", minHeight: 84.81}}>
<div style={{flex: 1}}> <div style={{flex: 1}}>
<h2>Your apps ({apps.length+searchableApps.length})</h2> <h2>Your apps ({apps.length+searchableApps.length})</h2>
</div> </div>
<Tooltip title={"Reload apps locally"} style={{marginTop: "28px", width: "100%"}} aria-label={"Upload"}> {isCloud ? null :
<Button <span>
variant="outlined" <Tooltip title={"Reload apps locally"} style={{marginTop: "28px", width: "100%"}} aria-label={"Upload"}>
component="label" <Button
color="primary" variant="outlined"
style={{margin: 5, maxHeight: 50, marginTop: 10}} component="label"
onClick={() => { color="primary"
hotloadApps() style={{margin: 5, maxHeight: 50, marginTop: 10}}
}} onClick={() => {
> hotloadApps()
<CachedIcon /> }}
</Button> >
</Tooltip> <CachedIcon />
<Tooltip title={"Download from Github"} style={{marginTop: "28px", width: "100%"}} aria-label={"Upload"}> </Button>
<Button </Tooltip>
variant="outlined" <Tooltip title={"Download from Github"} style={{marginTop: "28px", width: "100%"}} aria-label={"Upload"}>
component="label" <Button
color="primary" variant="outlined"
style={{margin: 5, maxHeight: 50, marginTop: 10}} component="label"
onClick={() => { color="primary"
setOpenApi(baseRepository) style={{margin: 5, maxHeight: 50, marginTop: 10}}
setLoadAppsModalOpen(true) onClick={() => {
}} setOpenApi(baseRepository)
> setLoadAppsModalOpen(true)
<CloudDownloadIcon /> }}
</Button> >
</Tooltip> <CloudDownloadIcon />
</Button>
</Tooltip>
</span>
}
</div> </div>
<TextField <TextField
style={{backgroundColor: inputColor}} style={{backgroundColor: inputColor}}
+9
View File
@@ -0,0 +1,9 @@
import React from 'react';
const HandlePayment = () => {
return (
null
)
}
export default HandlePayment