-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from DavidDurman/first-commit
First commit
- Loading branch information
Showing
9 changed files
with
320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"projects": { | ||
"default": "am-demo-embedded-integrations" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# This file was auto-generated by the Firebase CLI | ||
# https://github.com/firebase/firebase-tools | ||
|
||
name: Deploy to Firebase Hosting on merge | ||
'on': | ||
push: | ||
branches: | ||
- main | ||
jobs: | ||
build_and_deploy: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: FirebaseExtended/action-hosting-deploy@v0 | ||
with: | ||
repoToken: '${{ secrets.GITHUB_TOKEN }}' | ||
firebaseServiceAccount: >- | ||
${{ secrets.FIREBASE_SERVICE_ACCOUNT_AM_DEMO_EMBEDDED_INTEGRATIONS | ||
}} | ||
channelId: live | ||
projectId: am-demo-embedded-integrations |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Firebase cache | ||
.firebase/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"hosting": { | ||
"public": ".", | ||
"ignore": [ | ||
"firebase.json", | ||
"**/.*", | ||
"**/node_modules/**" | ||
], | ||
"rewrites": [ | ||
{ | ||
"source": "**", | ||
"destination": "/index.html" | ||
} | ||
] | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<html> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
<title>Appmixer Embed Integrations Demo</title> | ||
<link rel="stylesheet" type="text/css" href="./style.css"> | ||
</head> | ||
<body> | ||
<div class="container"> | ||
<div class="guide"> | ||
<img id="yoursaas" src="./yoursaas.svg" /> | ||
|
||
<h1>Appmixer Embedded Integrations Demo</h1> | ||
<p>This demo shows you how to embed Appmixer Integrations in your own web application.</p> | ||
|
||
<h2>1. Try the Appmixer Integrations UI</h2> | ||
<p>The Appmixer Integrations UI allows end-users of your application to browse and activate integrations that you pre-built for them in the Appmixer Studio.</p> | ||
<p><b>Try it yourself and activate an integration by clicking on the integration tile and configuring the integration.</b></p> | ||
</p> | ||
<p class="small">Note that this integration will run in the context of an Appmixer virtual user that was created for you in the background when you opened this page.</p> | ||
<p class="small">The Integration marketplace is rendered in the page natively, using the Appmixer JavaScript SDK. It is not included in an iframe.</p> | ||
|
||
<h2>2. Trigger the integration by sending an App Event</h2> | ||
<p>Once you have activated an integration, you can trigger it by sending an App Event to Appmixer (assuming your integration starts with the <code>OnAppEvent</code> trigger). This is normally done using the Appmixer JavaScript SDK or an HTTP request:</p> | ||
<pre> | ||
<code> | ||
appmixer.api.sendAppEvent('contact-created', { first: 'David', last: 'Doe' }); | ||
</code> | ||
or: | ||
<code> | ||
curl -XPOST \ | ||
-H 'Content-Type: application/json' \ | ||
-H "Authorization: Bearer VIRTUAL_USER_ACCESS_TOKEN" \ | ||
-d '{ "first": "David", "last": "Doe" }' \ | ||
"https://APPMIXER_TENANT_API_URL/plugins/appmixer/utils/appevents/events/contact-created" | ||
</code> | ||
</pre> | ||
<p><b>In this demo, you can send an App Event using the helper form below. This is to simulate a real-world scenario where you would send an App Event from your own application code.</b></p> | ||
|
||
<form class="app-event-form"> | ||
<label>App Event name</label><input class="app-event-event" type="text" value="contact-created" placeholder="contact-created" /> | ||
<label>App Event data (JSON)</label><textarea class="app-event-data" placeholder="JSON data">{ "first": "David", "last": "Doe" }</textarea> | ||
<input type="submit" value="Send App Event" /> | ||
</form> | ||
|
||
<a id="github-link" href="https://github.com/clientIO/appmixer-demo-embedded-integrations" target="_blank"><img src="./github-mark.svg" /></a> | ||
</div> | ||
<div class="app"> | ||
<div id="appmixer-integrations-marketplace"></div> | ||
<div id="appmixer-integrations-logs"></div> | ||
</div> | ||
</div> | ||
|
||
<script> | ||
function loadScript(url, callback) { | ||
const script = document.createElement('script'); | ||
script.src = url; | ||
script.onload = callback; | ||
script.onerror = console.error; | ||
document.head.appendChild(script); | ||
} | ||
|
||
// The Appmixer SDK is located at https://my.YOUR_TENANT.appmixer.cloud/appmixer/appmixer.js. | ||
const APPMIXER_STUDIO_URL = (new URLSearchParams(window.location.search)).get('studioUrl'); | ||
|
||
loadScript(APPMIXER_STUDIO_URL + '/appmixer/appmixer.js', () => { | ||
loadScript('./main.js'); | ||
}); | ||
</script> | ||
</body> | ||
</html> | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
const QUERY_PARAMS = new URLSearchParams(window.location.search); | ||
|
||
// This should have the pattern https://api.YOUR_TENANT.appmixer.cloud'; | ||
const APPMIXER_API_URL = QUERY_PARAMS.get('apiUrl'); | ||
|
||
let APPMIXER_VIRTUAL_USER_USERNAME = QUERY_PARAMS.get('username'); | ||
let APPMIXER_VIRTUAL_USER_TOKEN; | ||
let DOMAIN_FILTER = QUERY_PARAMS.get('domainFilter'); | ||
|
||
if (APPMIXER_VIRTUAL_USER_USERNAME) { | ||
// If username is provided in the query string of this demo, password must be provided as well. | ||
APPMIXER_VIRTUAL_USER_TOKEN = QUERY_PARAMS.get('token'); | ||
} else { | ||
// Hardcode one. Normally, you would generate this and store in your application code and pass it to the Appmixer SDK. | ||
// Note that Appmixer username can be any, even non-existing, email address. We're using a user ID | ||
// together with a fictional domain name. Appmixer does not send anything to these email addresses. | ||
// They are just used as a virtual user credentials pair. Moreover, the email domain | ||
// allows us to easily share integration templates with a specific group of users | ||
// (An alternative to this is to use the user scopes.) | ||
APPMIXER_VIRTUAL_USER_USERNAME = '[email protected]'; | ||
APPMIXER_VIRTUAL_USER_TOKEN = '4efaa8ec-ddc5-4852-b6cc-cb3039fe17b1'; | ||
} | ||
|
||
if (typeof Appmixer === 'undefined') { | ||
alert('Appmixer SDK not loaded. Are you sure you pointed to the right appmixer.js SDK location?'); | ||
} | ||
|
||
// Appmixer SDK instance. | ||
const appmixer = new Appmixer({ | ||
baseUrl: APPMIXER_API_URL, | ||
theme: { | ||
variables: { colors: { surface: '#f5f5f5' } } | ||
} | ||
}); | ||
|
||
const widgets = { | ||
integrations: null, | ||
wizard: null | ||
}; | ||
|
||
// Learn more about Appmixer virtual users at https://docs.appmixer.com/appmixer/tutorials/appmixer-virtual-users. | ||
async function ensureAppmixerVirtualUser(username, token) { | ||
let auth; | ||
try { | ||
auth = await appmixer.api.authenticateUser(username, token); | ||
appmixer.set('accessToken', auth.token); | ||
} catch (err) { | ||
if (err.response && err.response.status === 403) { | ||
// Virtual user not yet created in Appmixer. Create one. | ||
try { | ||
auth = await appmixer.api.signupUser(username, token); | ||
appmixer.set('accessToken', auth.token); | ||
} catch (err) { | ||
alert('Something went wrong creating a virtual user. ' + err.message); | ||
} | ||
} else { | ||
alert('Something went wrong authenticating a virtual user.'); | ||
} | ||
} | ||
} | ||
|
||
function createWidgets() { | ||
// Create Integrations Page widget. | ||
widgets.integrations = appmixer.ui.Integrations({ | ||
el: '#appmixer-integrations-marketplace', | ||
options: { | ||
showHeader: true, | ||
customFilter: [{ | ||
// Show only integration templates shared with users in this demo app. | ||
...(DOMAIN_FILTER && { 'sharedWith.0.domain': DOMAIN_FILTER }), | ||
type: 'integration' | ||
}, { | ||
userId: appmixer.get('user').id, | ||
templateId: '>0' | ||
//type: 'integration-instance' // Uncomment and remove line above once v6 is released. | ||
}] | ||
} | ||
}); | ||
widgets.integrations.on('integration:create', templateId => { | ||
widgets.wizard.close(); | ||
widgets.wizard.set('flowId', templateId); | ||
widgets.wizard.open(); | ||
}); | ||
widgets.integrations.on('integration:edit', integrationId => { | ||
widgets.wizard.close(); | ||
widgets.wizard.set('flowId', integrationId); | ||
widgets.wizard.open(); | ||
}); | ||
widgets.wizard = appmixer.ui.Wizard(); | ||
widgets.wizard.on('flow:start-after', () => widgets.integrations.reload()); | ||
widgets.wizard.on('flow:remove-after', () => { | ||
widgets.integrations.reload(); | ||
widgets.wizard.close(); | ||
}); | ||
} | ||
|
||
async function main() { | ||
await ensureAppmixerVirtualUser(APPMIXER_VIRTUAL_USER_USERNAME, APPMIXER_VIRTUAL_USER_TOKEN); | ||
createWidgets(); | ||
widgets.integrations.open(); | ||
|
||
document.querySelector('.app-event-form').addEventListener('submit', (evt) => { | ||
evt.preventDefault(); | ||
appmixer.api.sendAppEvent(document.querySelector('.app-event-event').value, JSON.parse(document.querySelector('.app-event-data').value)); | ||
}); | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
body { | ||
font-family: "IBM Plex Sans", "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif; | ||
} | ||
.container { | ||
display: flex; | ||
margin: 20px; | ||
} | ||
.guide { | ||
flex: 2; | ||
padding: 50px; | ||
position: relative; | ||
} | ||
.app { | ||
flex: 2; | ||
position: relative; | ||
border: 2px dashed #F3153C; | ||
} | ||
#yoursaas { | ||
position: absolute; | ||
right: 3px; | ||
top: 10px; | ||
width: 150px; | ||
} | ||
#github-link img { | ||
position: absolute; | ||
left: 50px; | ||
top: 20px; | ||
width: 30px; | ||
} | ||
.guide p { | ||
font-size: 16px; | ||
line-height: 1.5; | ||
max-width: 80%; | ||
} | ||
.guide p.small { | ||
font-size: 14px; | ||
color: #666; | ||
} | ||
.guide p b { | ||
color: #007bff; | ||
} | ||
input, select, textarea { | ||
display: block; | ||
box-sizing: border-box; | ||
width: 100%; | ||
border-radius: 0; | ||
} | ||
.app-event-form { | ||
max-width: 400px; | ||
padding: 20px; | ||
border: 1px solid #f5f5f5; | ||
box-shadow: 2px 8px 14px gray; | ||
} | ||
.app-event-form { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 10px; | ||
} | ||
.app-event-form input, | ||
.app-event-form textarea { | ||
padding: 10px; | ||
border: 2px solid #007bff; | ||
border-radius: 5px; | ||
outline: none; | ||
} | ||
.app-event-form input[type="submit"] { | ||
padding: 10px; | ||
border: none; | ||
border-radius: 5px; | ||
background-color: #007bff; | ||
color: white; | ||
cursor: pointer; | ||
} | ||
.app-event-form input[type="submit"]:hover { | ||
background-color: #0056b3; | ||
} | ||
#appmixer-integrations-marketplace { | ||
position: absolute; | ||
inset: 0; | ||
} | ||
.am-integrations { | ||
padding: 50px; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.