diff --git a/backend/go-app/main.go b/backend/go-app/main.go
index 97613010..f3b3f789 100644
--- a/backend/go-app/main.go
+++ b/backend/go-app/main.go
@@ -74,7 +74,8 @@ var baseAppPath = "/home/frikky/git/shaffuru/tmp/apps"
var baseDockerName = "frikky/shuffle"
//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
diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go
index baa32501..0b95ed20 100644
--- a/backend/go-app/walkoff.go
+++ b/backend/go-app/walkoff.go
@@ -68,15 +68,19 @@ type ExecutionRequest struct {
}
type SyncFeatures struct {
- Webhook SyncData `json:"webhook" datastore:"webhook"`
- Schedule SyncData `json:"schedule" datastore:"schedule"`
- UserInput SyncData `json:"user_input" datastore:"user_input"`
- EmailTrigger SyncData `json:"email_trigger" datastore:"email_trigger"`
- Apps SyncData `json:"apps" datastore:"apps"`
- Workflows SyncData `json:"workflows" datastore:"workflows"`
- Schedules SyncData `json:"schedules" datastore:"schedules"`
- Autocomplete SyncData `json:"autocomplete" datastore:"autocomplete"`
- Authentication SyncData `json:"authentication" datastore:"authentication"`
+ Webhook SyncData `json:"webhook" datastore:"webhook"`
+ Schedules SyncData `json:"schedules" datastore:"schedules"`
+ UserInput SyncData `json:"user_input" datastore:"user_input"`
+ SendMail SyncData `json:"send_mail" datastore:"send_mail"`
+ SendSms SyncData `json:"send_sms" datastore:"send_sms"`
+ EmailTrigger SyncData `json:"email_trigger" datastore:"email_trigger"`
+ AppExecutions SyncData `json:"app_executions" datastore:"app_executions"`
+ WorkflowExecutions SyncData `json:"workflow_executions" datastore:"workflow_executions"`
+ 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 {
@@ -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
+ _ = triggerInformation
if strings.Contains(triggerType, "email") {
if email == "test@test.com" {
log.Printf("Email isn't specified during save.")
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 668324d8..5bdda5b9 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -100,7 +100,7 @@ const App = (message, props) => {
//console.log(responseJson.success)
setUserData(responseJson)
setIsLoggedIn(true)
- console.log("Cookies: ", cookies)
+ //console.log("Cookies: ", cookies)
// Updating cookie every request
for (var key in responseJson["cookies"]) {
diff --git a/frontend/src/components/history.jsx b/frontend/src/components/history.jsx
new file mode 100644
index 00000000..71ce4bd5
--- /dev/null
+++ b/frontend/src/components/history.jsx
@@ -0,0 +1,8 @@
+import { createBrowserHistory } from 'history';
+
+var localExport
+if (typeof window !== 'undefined') {
+ localExport = createBrowserHistory({forceRefresh: true});
+}
+
+export default localExport
diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx
index 45a77e03..25b9ead8 100644
--- a/frontend/src/views/Admin.jsx
+++ b/frontend/src/views/Admin.jsx
@@ -75,6 +75,9 @@ const Admin = (props) => {
const [users, setUsers] = React.useState([]);
const [organizations, setOrganizations] = 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 [authentication, setAuthentication] = React.useState([]);
@@ -86,6 +89,7 @@ const Admin = (props) => {
const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false)
const [showArchived, setShowArchived] = React.useState(false)
+ const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
const getApps = () => {
fetch(globalUrl+"/api/v1/workflows/apps", {
method: 'GET',
@@ -275,7 +279,7 @@ const Admin = (props) => {
style={{ width: 150, height: 55, flex: 1 }}
variant="contained"
color="primary"
- onClick={() => handleEditOrg(selectedOrganization.name, selectedOrganization.description, selectedOrganization.id, selectedOrganization.image)}
+ onClick={() => handleEditOrg(orgName, orgDescription, selectedOrganization.id, selectedOrganization.image)}
>
Save Changes
@@ -303,7 +307,7 @@ const Admin = (props) => {
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
- alert.error("Failed updating org")
+ alert.error("Failed updating org: ", responseJson.reason)
} else {
alert.success("Successfully edited org!")
setSelectedUserModalOpen(false)
@@ -386,37 +390,44 @@ const Admin = (props) => {
'Content-Type': 'application/json',
},
})
- .then(response =>
- response.json().then(responseJson => {
- if (responseJson["success"] === false) {
- alert.error("Failed getting org: ", responseJson.readon)
- } else {
- setSelectedOrganization(responseJson)
- var lists = {
- "active": {
- "triggers": [],
- "features": [],
- "sync": [],
- },
- "inactive": {
- "triggers": [],
- "features": [],
- "sync": [],
- },
- }
+ .then(response => {
+ if (response.status === 401) {
+ }
- Object.keys(responseJson.sync_features).map(function(key, index) {
- //console.log(responseJson.sync_features[key])
- })
-
-
- if (responseJson.image !== undefined && responseJson.image !== null && responseJson.image.length > 0) {
- setFileBase64(responseJson.image)
- }
- setOrganizationFeatures(lists)
+ return response.json()
+ })
+ .then(responseJson => {
+ if (responseJson["success"] === false) {
+ alert.error("Failed getting org: ", responseJson.readon)
+ } else {
+ setSelectedOrganization(responseJson)
+ var 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 => {
console.log("Error getting org: ", error)
alert.error("Error getting current organization")
@@ -629,7 +640,7 @@ const Admin = (props) => {
})
.then((responseJson) => {
if (responseJson.success) {
- console.log(responseJson.data)
+ //console.log(responseJson.data)
setAuthentication(responseJson.data)
} else {
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) {
setFirstRequest(false)
- getUsers()
+ if (!isCloud) {
+ getUsers()
+ } else {
+ getSettings()
+ }
const views = {
"organization": 0,
@@ -737,7 +777,7 @@ const Admin = (props) => {
}
if (selectedOrganization.id === undefined && userdata !== undefined && userdata.active_org !== undefined) {
- //setSelectedOrganization(userdata.active_org)
+ setSelectedOrganization(userdata.active_org)
handleGetOrg(userdata.active_org.id)
}
@@ -1120,8 +1160,51 @@ const Admin = (props) => {
var imageData = file.length > 0 ? file : fileBase64
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 =
- const organizationView = curTab === 0 ?
+ const organizationView = curTab === 0 && selectedOrganization.id !== undefined ?
Organization overview
@@ -1130,17 +1213,18 @@ const Admin = (props) => {
{selectedOrganization.id === undefined ?
- null :
+
+ :
-
+
0 ? null : "1px solid #f85a3e", cursor: "pointer", backgroundColor: imageData !== undefined && imageData.length > 0 ? null : theme.palette.inputColor, maxWidth: 174, maxHeight: 174}} onClick={() => {upload.click()}}>
upload = ref} onChange={editHeaderImage} />
{imageInfo}
-
+
Name
{
id="standard-required"
margin="normal"
variant="outlined"
- defaultValue={selectedOrganization.name}
+ value={orgName}
onChange={e => {
const invalid = ["#", ":", "."]
for (var key in invalid) {
@@ -1166,8 +1250,7 @@ const Admin = (props) => {
return
}
- selectedOrganization.name = e.target.value
- setSelectedOrganization(selectedOrganization)
+ setOrgName(e.target.value)
}}
color="primary"
InputProps={{
@@ -1193,10 +1276,9 @@ const Admin = (props) => {
margin="normal"
variant="outlined"
placeholder="A description for the service"
- defaultValue={selectedOrganization.description}
+ value={orgDescription}
onChange={e => {
- selectedOrganization.description = e.target.value
- setSelectedOrganization(selectedOrganization)
+ setOrgDescription(e.target.value)
}}
InputProps={{
classes: {
@@ -1214,65 +1296,110 @@ const Admin = (props) => {
-
-
Cloud syncronization
- What does
cloud sync do? Cloud syncronization is a way of getting more out of Shuffle. Shuffle will
ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach.
-
-
{
- setCloudSyncApikey(event.target.value)
- }}
- />
- {
- setLoading(true)
- enableCloudSync(
- cloudSyncApikey,
- selectedOrganization,
- selectedOrganization.cloud_sync,
- )
- }} color="primary">
- {selectedOrganization.cloud_sync ?
- "Stop sync"
- :
- "Start sync"
+ Cloud syncronization
+ What does cloud sync do? Cloud syncronization is a way of getting more out of Shuffle. Shuffle will ALWAYS make every option open source, but features relying on other users can't be done without a collaborative approach.
+
+ {isCloud ?
+
+
+
+ Currently syncronizing: {selectedOrganization.cloud_sync_active === true ? "True" : "False"}
+
+ {selectedOrganization.cloud_sync_active ?
+
+ Syncronization interval: {selectedOrganization.sync_config.interval === 0 ? "60" : selectedOrganization.sync_config.interval}
+
+ :
+ null
}
-
+
+ Your Apikey
+
+
+
- {orgSyncResponse.length > 0 ?
-
- Error from Shuffle: {orgSyncResponse}
-
- : null
- }
- {/*
-
- {syncList.map((data, index) => {
- return (
-
- )
- })}
-
- */}
- Cloud sync features
+ :
+
+
+ {
+ setCloudSyncApikey(event.target.value)
+ }}
+ />
+ {
+ setLoading(true)
+ enableCloudSync(
+ cloudSyncApikey,
+ selectedOrganization,
+ selectedOrganization.cloud_sync,
+ )
+ }} color="primary">
+ {selectedOrganization.cloud_sync ?
+ "Stop sync"
+ :
+ "Start sync"
+ }
+
+
+ {orgSyncResponse.length > 0 ?
+
+ Error from Shuffle: {orgSyncResponse}
+
+ : null
+ }
+ {/*
+
+ {syncList.map((data, index) => {
+ return (
+
+ )
+ })}
+
+ */}
+
+ }
+ Cloud sync features
{Object.keys(selectedOrganization.sync_features).map(function(key, index) {
+ if (key === "schedule") {
+ return null
+ }
//
const item = selectedOrganization.sync_features[key]
@@ -1290,8 +1417,51 @@ const Admin = (props) => {
)
})}
+
+ {isCloud && selectedOrganization.subscriptions !== null && selectedOrganization.subscriptions.length > 0 ?
+
+
+ Your subscription{selectedOrganization.subscriptions.length > 1 ? "s" : ""}
+
+
+ {selectedOrganization.subscriptions.reverse().map((sub, index) => {
+ return (
+
+
+ Type : {sub.level}
+ Recurrence : {sub.recurrence}
+ {sub.active ?
+
+
Started : {new Date(sub.startdate*1000).toISOString()}
+
{
+ cancelSubscriptions(sub.reference)
+ }}>
+ Cancel subscription
+
+
+ :
+
+
Cancelled : {new Date(sub.cancellationdate*1000).toISOString()}
+
+ Status : Deactivated
+
+
+ }
+
+
+ )
+ })}
+
+
+
+ : null
+ }
}
+
+
+
+
: null
@@ -1508,7 +1678,11 @@ const Admin = (props) => {
+
{
style={{maxWidth: 200}}
primary={schedule.seconds}
/>
+
{
// primary={environment.Registered ? "true" : "false"}
const setConfig = (event, newValue) => {
- if (newValue === 2) {
+ if (newValue === 1) {
+ getUsers()
+ } else if (newValue === 2) {
getAppAuthentication()
} else if (newValue === 3) {
getEnvironments()
@@ -1980,10 +2160,10 @@ const Admin = (props) => {
aria-label="disabled tabs example"
>
Organization/>
- Users />
- App Authentication/>
- Environments/>
- Schedules />
+ {isCloud ? null : Users />}
+ {isCloud ? null : App Authentication/>}
+ {isCloud ? null : Environments/>}
+ {isCloud ? null : Schedules />}
{window.location.protocol == "http:" && window.location.port === "3000" ? Hybrid/> : null}
{window.location.protocol == "http:" && window.location.port === "3000" ? Organizations/> : null}
{window.location.protocol === "http:" && window.location.port === "3000" ? Categories/> : null}
diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx
index 7aff28dc..2f10d25e 100644
--- a/frontend/src/views/AngularWorkflow.jsx
+++ b/frontend/src/views/AngularWorkflow.jsx
@@ -191,6 +191,7 @@ const AngularWorkflow = (props) => {
const cloudSyncEnabled = props.userdata !== undefined && props.userdata.active_org !== null && props.userdata.active_org !== undefined ? props.userdata.active_org.cloud_sync === true : false
const triggerEnvironments = cloudSyncEnabled ? ["cloud", "onprem"] : environments
+ const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
const unloadText = 'Are you sure you want to leave without saving (CTRL+S)?'
useBeforeunload(() => {
@@ -997,12 +998,15 @@ const AngularWorkflow = (props) => {
setSelectedApp(curapp)
}
- var env = environments.find(a => a.Name === curaction.environment)
- if (!env || env === undefined) {
- env = environments[defaultEnvironmentIndex]
+ if (environments !== undefined) {
+ var env = environments.find(a => a.Name === curaction.environment)
+ if (!env || env === undefined) {
+ env = environments[defaultEnvironmentIndex]
+ }
+
+ setSelectedActionEnvironment(env)
}
- setSelectedActionEnvironment(env)
setSelectedActionName(curaction.name)
setSelectedAction(curaction)
@@ -1265,6 +1269,11 @@ const AngularWorkflow = (props) => {
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for apps :O!")
+ if (isCloud) {
+ setEnvironments({"name": "Cloud", "type": "cloud"})
+ } else {
+ setEnvironments({"name": "Onprem", "type": "onprem"})
+ }
return
}
@@ -1949,7 +1958,7 @@ const AngularWorkflow = (props) => {
"errors": null,
"is_valid": true ? false : cloudSyncEnabled,
"label": "Email",
- "environment": environments[defaultEnvironmentIndex] === undefined ? {} : environments[defaultEnvironmentIndex].Name,
+ "environment": "cloud",
"large_image": 'data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/hAytodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Nzg4QTJBMjVEMDI1MTFFN0EwQUVDODc5QjYyQkFCMUQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Nzg4QTJBMjZEMDI1MTFFN0EwQUVDODc5QjYyQkFCMUQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3ODhBMkEyM0QwMjUxMUU3QTBBRUM4NzlCNjJCQUIxRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3ODhBMkEyNEQwMjUxMUU3QTBBRUM4NzlCNjJCQUIxRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/bAEMAAwICAgICAwICAgMDAwMEBgQEBAQECAYGBQYJCAoKCQgJCQoM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',
"long_description": "Execute a workflow when you get an email",
}]
diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx
index 7d159d04..9bb8dda4 100644
--- a/frontend/src/views/Apps.jsx
+++ b/frontend/src/views/Apps.jsx
@@ -137,6 +137,7 @@ const Apps = (props) => {
const [isDropzone, setIsDropzone] = React.useState(false);
const upload = React.useRef(null);
+ const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" ? true : false
const { start, stop } = useInterval({
duration: 5000,
@@ -592,7 +593,7 @@ const Apps = (props) => {
{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) ?
{downloadButton}
{editButton}
@@ -618,7 +619,7 @@ const Apps = (props) => {
})}
: null}
- {props.userdata.id === selectedApp.owner ?
+ {props.userdata !== undefined && props.userdata.id === selectedApp.owner ?
{/*
ID: {selectedApp.id}
*/}
Sharing:
@@ -794,7 +795,7 @@ const Apps = (props) => {
}
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 reader = new FileReader();
@@ -846,37 +847,41 @@ const Apps = (props) => {
-
+
Your apps ({apps.length+searchableApps.length})
-
- {
- hotloadApps()
- }}
- >
-
-
-
-
- {
- setOpenApi(baseRepository)
- setLoadAppsModalOpen(true)
- }}
- >
-
-
-
+ {isCloud ? null :
+
+
+ {
+ hotloadApps()
+ }}
+ >
+
+
+
+
+ {
+ setOpenApi(baseRepository)
+ setLoadAppsModalOpen(true)
+ }}
+ >
+
+
+
+
+ }
{
+ return (
+ null
+ )
+}
+
+export default HandlePayment