Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into fix/missing-functionalities fix: refreshing issue feat: implement devices screen Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into fix/missing-functionalities feat: implement new layout Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into fix/missing-functionalities feat: implement new layout fix: header fix: showing error on add ssh modal fix: login by enter key Co-authored-by: Tyler <everdev0923@gmail.com> Reviewed-on: https://git.bubblev.org/bubblev/bubble-web/pulls/61pull/68/head
@@ -2524,6 +2524,11 @@ | |||
"entities": "^1.1.1" | |||
} | |||
}, | |||
"dom-walk": { | |||
"version": "0.1.2", | |||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", | |||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" | |||
}, | |||
"domain-browser": { | |||
"version": "1.2.0", | |||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", | |||
@@ -3432,6 +3437,15 @@ | |||
} | |||
} | |||
}, | |||
"global": { | |||
"version": "4.4.0", | |||
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", | |||
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", | |||
"requires": { | |||
"min-document": "^2.19.0", | |||
"process": "^0.11.10" | |||
} | |||
}, | |||
"global-modules": { | |||
"version": "2.0.0", | |||
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", | |||
@@ -4550,6 +4564,14 @@ | |||
"mime-db": "1.44.0" | |||
} | |||
}, | |||
"min-document": { | |||
"version": "2.19.0", | |||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", | |||
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", | |||
"requires": { | |||
"dom-walk": "^0.1.0" | |||
} | |||
}, | |||
"minimalistic-assert": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", | |||
@@ -5504,8 +5526,7 @@ | |||
"process": { | |||
"version": "0.11.10", | |||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", | |||
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", | |||
"dev": true | |||
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" | |||
}, | |||
"process-nextick-args": { | |||
"version": "2.0.1", | |||
@@ -7665,6 +7686,23 @@ | |||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", | |||
"integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" | |||
}, | |||
"vue-carousel": { | |||
"version": "0.18.0", | |||
"resolved": "https://registry.npmjs.org/vue-carousel/-/vue-carousel-0.18.0.tgz", | |||
"integrity": "sha512-a2zxh7QJioDxNMguqcuJ7TPbfgK5bGDaAXIia7NWxPAWsEvNE4ZtHgsGu40L5Aha4uyjmNKXvleB14QAXFoKig==", | |||
"requires": { | |||
"global": "^4.3.2", | |||
"regenerator-runtime": "^0.12.1", | |||
"vue": "^2.5.17" | |||
}, | |||
"dependencies": { | |||
"regenerator-runtime": { | |||
"version": "0.12.1", | |||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", | |||
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" | |||
} | |||
} | |||
}, | |||
"vue-click-outside": { | |||
"version": "1.1.0", | |||
"resolved": "https://registry.npmjs.org/vue-click-outside/-/vue-click-outside-1.1.0.tgz", | |||
@@ -31,7 +31,11 @@ | |||
<!-- Navigation --> | |||
<div class="navigation"> | |||
<router-link to="/bubble" class="navigation-item" @click.native="closeMenu()"> | |||
<router-link | |||
to="/bubble" | |||
class="navigation-item" | |||
@click.native="closeMenu()" | |||
> | |||
<i class="fa fa-home icon icon-home"></i> | |||
<span>{{ messages.label_menu_network }}</span> | |||
</router-link> | |||
@@ -72,16 +76,24 @@ | |||
<span>{{ messages.label_menu_settings }}</span> | |||
</router-link> --> | |||
<router-link to="/support" class="navigation-item" @click.native="closeMenu()"> | |||
<router-link | |||
to="/support" | |||
class="navigation-item" | |||
@click.native="closeMenu()" | |||
> | |||
<i class="fa fa-question-circle icon icon-help"></i> | |||
<span>{{ messages.label_menu_help }}</span> | |||
</router-link> | |||
</div> | |||
<!-- Upgrade Plan --> | |||
<div class="flex-grow-1"></div> | |||
<!-- <div class="flex-grow-1"></div> --> | |||
<!-- Logout --> | |||
<router-link to="/logout" class="logout-button" @click.native="closeMenu()"> | |||
<router-link | |||
to="/logout" | |||
class="logout-button" | |||
@click.native="closeMenu()" | |||
> | |||
<Button color="outline" block> | |||
{{ messages.log_out }} | |||
</Button> | |||
@@ -281,7 +293,7 @@ export default { | |||
closeMenu() { | |||
console.log('click.nativeed'); | |||
this.menuVisible = false; | |||
} | |||
}, | |||
}, | |||
}; | |||
</script> |
@@ -1,8 +1,173 @@ | |||
<!-- Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ --> | |||
<template> | |||
<router-view></router-view> | |||
<router-view v-if="isPageAvailable"></router-view> | |||
</template> | |||
<script> | |||
export default {}; | |||
import { mapState, mapActions } from 'vuex'; | |||
import { util } from '~/_helpers'; | |||
import { isAuthenticator, isNotAuthenticator } from '~/_store/users.module'; | |||
export default { | |||
data: () => ({ | |||
verifiedContacts: null, | |||
verifiedContactRefresher: null, | |||
accountPlan: { | |||
currentUser: null, | |||
name: '', | |||
domain: '', | |||
locale: null, | |||
timezone: '', | |||
plan: 'bubble', | |||
footprint: 'Worldwide', | |||
paymentMethodObject: { | |||
uuid: null, | |||
paymentMethodType: null, | |||
paymentInfo: null, | |||
}, | |||
sshKey: '', | |||
forkHost: '', | |||
syncAccount: true, | |||
launchLock: false, | |||
sendErrors: true, | |||
sendMetrics: true, | |||
}, | |||
payMethods: null, | |||
}), | |||
computed: { | |||
...mapState('users', ['policy']), | |||
...mapState('paymentMethods', ['accountPaymentMethods']), | |||
...mapState('system', ['configs', 'messages']), | |||
isPageAvailable() { | |||
return ( | |||
!this.currentUser || (this.verifiedContacts || this.currentUser.admin) | |||
); | |||
}, | |||
}, | |||
created() { | |||
this.currentUser = util.currentUser(); | |||
if (this.currentUser) { | |||
this.locale = this.currentUser.locale; | |||
} | |||
}, | |||
mounted() { | |||
this.initDefaults(); | |||
}, | |||
methods: { | |||
...mapActions('users', ['getPolicyByUserId']), | |||
...mapActions('paymentMethods', ['getAllAccountPaymentMethods']), | |||
initDefaults() { | |||
const selectedLocale = | |||
this.currentUser !== null && | |||
typeof this.currentUser.locale !== 'undefined' && | |||
this.currentUser.locale !== null | |||
? this.currentUser.locale | |||
: 'detect'; | |||
if (this.currentUser && !this.currentUser.admin) { | |||
this.getPolicyByUserId({ | |||
userId: this.currentUser.uuid, | |||
messages: this.messages, | |||
errors: this.errors, | |||
}); | |||
} | |||
}, | |||
hasVerifiedContact(policy) { | |||
if (policy && policy.accountContacts) { | |||
const contacts = policy.accountContacts; | |||
for (let i = 0; i < contacts.length; i++) { | |||
if (contacts[i].verified && isNotAuthenticator(contacts[i])) | |||
return true; | |||
} | |||
return false; | |||
} | |||
return false; | |||
}, | |||
navigateToVerifyEmail() { | |||
if (this.$route.path !== '/verifyEmail') { | |||
this.$router.push('/verifyEmail'); | |||
} | |||
}, | |||
navigateToPaymentPage() { | |||
if (this.$route.path !== '/payment') { | |||
this.$router.push('/payment'); | |||
} | |||
}, | |||
navigateToDashboard() { | |||
if ( | |||
this.$route.path === '/payment' || | |||
this.$route.path === '/verifyEmail' | |||
) { | |||
this.$router.push('/'); | |||
} | |||
}, | |||
}, | |||
watch: { | |||
policy(p) { | |||
this.verifiedContacts = this.hasVerifiedContact(p); | |||
const currentUser = util.currentUser(); | |||
if (!this.verifiedContacts && !currentUser.admin) { | |||
this.navigateToVerifyEmail(); | |||
if (this.verifiedContactRefresher === null) { | |||
const vue = this; | |||
const currentUser = util.currentUser(); | |||
this.verifiedContactRefresher = window.setInterval(() => { | |||
vue.getPolicyByUserId({ | |||
userId: currentUser.uuid, | |||
messages: vue.messages, | |||
errors: vue.errors, | |||
}); | |||
}, 5000); | |||
} | |||
} else { | |||
const currentUser = util.currentUser(); | |||
this.getAllAccountPaymentMethods({ | |||
userId: currentUser.uuid, | |||
messages: this.messages, | |||
errors: this.errors, | |||
}); | |||
if (this.verifiedContactRefresher !== null) { | |||
window.clearInterval(this.verifiedContactRefresher); | |||
this.verifiedContactRefresher = null; | |||
} | |||
} | |||
}, | |||
accountPaymentMethods(pms, oldpms) { | |||
if (pms && this.configs.paymentsEnabled) { | |||
const payMethods = []; | |||
for (let i = 0; i < pms.length; i++) { | |||
const pm = pms[i]; | |||
if ( | |||
(typeof pm.promotion === 'undefined' || | |||
pm.promotion === null || | |||
!pm.promotion) && | |||
(typeof pm.deleted === 'undefined' || pm.deleted === null) | |||
) { | |||
payMethods.push(pm); | |||
} | |||
} | |||
if ( | |||
this.accountPlan.paymentMethodObject.uuid === null && | |||
payMethods.length > 0 | |||
) { | |||
this.navigateToDashboard(); | |||
} else { | |||
this.navigateToPaymentPage(); | |||
} | |||
} | |||
}, | |||
}, | |||
}; | |||
</script> |
@@ -220,6 +220,7 @@ export default { | |||
paymentMethodObject: null, | |||
confirmPassword: '', | |||
submitted: false, | |||
preferredPlan: null, | |||
}; | |||
}, | |||
@@ -314,6 +315,7 @@ export default { | |||
receivePromotionalMessages: this.receivePromotionalMessages, | |||
agreeToTerms: this.agreeToTerms, | |||
promoCode: this.promoCode, | |||
preferredPlan: this.preferredPlan, | |||
}, | |||
messages: this.messages, | |||
errors: this.errors, | |||
@@ -346,7 +348,7 @@ export default { | |||
}, | |||
plan(p) { | |||
if (p.uuid) { | |||
this.user.preferredPlan = p.uuid; | |||
this.preferredPlan = p.uuid; | |||
} | |||
}, | |||
configs(configs) { | |||
@@ -56,7 +56,7 @@ | |||
import { mapState, mapActions } from 'vuex'; | |||
import Lottie from 'lottie-web'; | |||
import { util } from '~/_helpers' | |||
import { util } from '~/_helpers'; | |||
import { Features } from '~/_components/sections'; | |||
// convenience methods | |||
@@ -1,6 +1,6 @@ | |||
<!-- Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ --> | |||
<template> | |||
<div class="container-fluid"> | |||
<div class="container-fluid" v-if="isPageAvailable"> | |||
<img src="/bubble_bkgrnd.png" alt="" class="background-image" /> | |||
<div class="content"> | |||
<Sidebar /> | |||
@@ -80,166 +80,58 @@ header { | |||
<script> | |||
import { mapState, mapActions } from 'vuex'; | |||
import { util } from '~/_helpers'; | |||
import { isAuthenticator, isNotAuthenticator } from '~/_store/users.module'; | |||
import { Footer, Notification, Sidebar } from '~/_components/layout'; | |||
import { Footer, Notification, Sidebar } from '~/_components/layout'; | |||
export default { | |||
components: { | |||
Footer, | |||
Notification, | |||
Sidebar, | |||
}, | |||
data: () => ({ | |||
verifiedContacts: null, | |||
verifiedContactRefresher: null, | |||
accountPlan: { | |||
currentUser: null, | |||
name: '', | |||
domain: '', | |||
locale: null, | |||
timezone: '', | |||
plan: 'bubble', | |||
footprint: 'Worldwide', | |||
paymentMethodObject: { | |||
uuid: null, | |||
paymentMethodType: null, | |||
paymentInfo: null, | |||
}, | |||
sshKey: '', | |||
forkHost: '', | |||
syncAccount: true, | |||
launchLock: false, | |||
sendErrors: true, | |||
sendMetrics: true, | |||
}, | |||
payMethods: null, | |||
currentUser: null, | |||
hasPaymentMethod: false, | |||
}), | |||
computed: { | |||
...mapState('users', ['policy']), | |||
...mapState('paymentMethods', ['accountPaymentMethods']), | |||
...mapState('system', ['configs', 'messages']), | |||
isPageAvailable() { | |||
return !this.configs.paymentsEnabled || this.hasPaymentMethod; | |||
}, | |||
}, | |||
created() { | |||
this.currentUser = util.currentUser(); | |||
this.locale = this.currentUser.locale; | |||
}, | |||
mounted() { | |||
this.initDefaults(); | |||
}, | |||
methods: { | |||
...mapActions('users', ['getPolicyByUserId']), | |||
...mapActions('paymentMethods', ['getAllAccountPaymentMethods']), | |||
initDefaults() { | |||
const selectedLocale = | |||
this.currentUser !== null && | |||
typeof this.currentUser.locale !== 'undefined' && | |||
this.currentUser.locale !== null | |||
? this.currentUser.locale | |||
: 'detect'; | |||
if (!this.currentUser.admin) { | |||
this.getPolicyByUserId({ | |||
userId: this.currentUser.uuid, | |||
messages: this.messages, | |||
errors: this.errors, | |||
}); | |||
} | |||
}, | |||
hasVerifiedContact(policy) { | |||
if (policy && policy.accountContacts) { | |||
const contacts = policy.accountContacts; | |||
for (let i = 0; i < contacts.length; i++) { | |||
if (contacts[i].verified && isNotAuthenticator(contacts[i])) | |||
return true; | |||
if (this.configs.paymentsEnabled) { | |||
this.hasPaymentMethod = true; | |||
} | |||
if (this.accountPaymentMethods && this.configs.paymentsEnabled) { | |||
const payMethods = []; | |||
Array.from(this.accountPaymentMethods).forEach((pm) => { | |||
if ( | |||
(typeof pm.promotion === 'undefined' || | |||
pm.promotion === null || | |||
!pm.promotion) && | |||
(typeof pm.deleted === 'undefined' || pm.deleted === null) | |||
) { | |||
payMethods.push(pm); | |||
} | |||
return false; | |||
} | |||
return false; | |||
}, | |||
}); | |||
navigateToVerifyEmail() { | |||
if (this.$route.path !== '/verifyEmail') { | |||
this.$router.push('/verifyEmail'); | |||
if (payMethods.length > 0) { | |||
this.hasPaymentMethod = true; | |||
} | |||
}, | |||
navigateToPaymentPage() { | |||
if (this.$route.path !== '/payment') { | |||
this.$router.push('/payment'); | |||
} | |||
}, | |||
navigateToDashboard() { | |||
if ( | |||
this.$route.path === '/payment' || | |||
this.$route.path === '/verifyEmail' | |||
) { | |||
this.$router.push('/'); | |||
} | |||
}, | |||
} | |||
}, | |||
watch: { | |||
policy(p) { | |||
this.verifiedContacts = this.hasVerifiedContact(p); | |||
const currentUser = util.currentUser(); | |||
if (!this.verifiedContacts && !currentUser.admin) { | |||
this.navigateToVerifyEmail(); | |||
if (this.verifiedContactRefresher === null) { | |||
const vue = this; | |||
const currentUser = util.currentUser(); | |||
this.verifiedContactRefresher = window.setInterval(() => { | |||
vue.getPolicyByUserId({ | |||
userId: currentUser.uuid, | |||
messages: vue.messages, | |||
errors: vue.errors, | |||
}); | |||
}, 5000); | |||
} | |||
} else { | |||
const currentUser = util.currentUser(); | |||
this.getAllAccountPaymentMethods({ | |||
userId: currentUser.uuid, | |||
messages: this.messages, | |||
errors: this.errors, | |||
}); | |||
if (this.verifiedContactRefresher !== null) { | |||
window.clearInterval(this.verifiedContactRefresher); | |||
this.verifiedContactRefresher = null; | |||
} | |||
} | |||
}, | |||
accountPaymentMethods(pms, oldpms) { | |||
if (pms && this.configs.paymentsEnabled) { | |||
const payMethods = []; | |||
for (let i = 0; i < pms.length; i++) { | |||
const pm = pms[i]; | |||
if ( | |||
(typeof pm.promotion === 'undefined' || | |||
pm.promotion === null || | |||
!pm.promotion) && | |||
(typeof pm.deleted === 'undefined' || pm.deleted === null) | |||
) { | |||
payMethods.push(pm); | |||
} | |||
} | |||
if ( | |||
this.accountPlan.paymentMethodObject.uuid === null && | |||
payMethods.length > 0 | |||
) { | |||
this.navigateToDashboard(); | |||
} else { | |||
this.navigateToPaymentPage(); | |||
} | |||
} | |||
}, | |||
methods: { | |||
...mapActions('paymentMethods', ['getAllAccountPaymentMethods']), | |||
...mapState('paymentMethods', ['accountPaymentMethods']), | |||
}, | |||
}; | |||
</script> |
@@ -91,28 +91,6 @@ export const router = new Router({ | |||
component: () => import('~/_pages/main/Layout'), | |||
children: [ | |||
{ path: '', component: DashboardPage }, | |||
{ | |||
path: 'me/download/:uuid', | |||
redirect: (r) => ({ | |||
path: 'me/policy', | |||
query: { download: r.params.uuid }, | |||
}), | |||
}, | |||
{ path: 'me/action', component: ActionPage }, | |||
{ path: 'apps', component: AppsPage }, | |||
{ path: 'app/:app', component: AppPage }, | |||
{ path: 'app/:app/config/:view', component: AppConfigPage }, | |||
{ | |||
path: 'app/:app/config/:view/:item', | |||
component: AppConfigPage, | |||
}, | |||
{ path: 'app/:app/view/:view', component: AppDataViewPage }, | |||
{ path: 'app/:app/site/:site', component: AppSitePage }, | |||
{ | |||
path: 'app/:app/site/:site/view/:view', | |||
component: AppDataViewPage, | |||
}, | |||
{ path: 'notifications', component: NotificationsPage }, | |||
{ | |||
path: 'bubble', | |||
component: () => import('~/_pages/main/bubble/MyBubble'), | |||
@@ -293,7 +271,7 @@ const publicPages = [ | |||
'/activate', | |||
'/legal', | |||
// new Pages | |||
'/me/action', | |||
]; | |||
router.beforeEach((to, from, next) => { | |||