diff --git a/src/phpunit.xml b/src/phpunit.xml --- a/src/phpunit.xml +++ b/src/phpunit.xml @@ -23,24 +23,7 @@ tests/Browser - tests/Browser/Reseller/DashboardTest.php - tests/Browser/Reseller/DistlistTest.php - tests/Browser/Reseller/DomainTest.php - tests/Browser/Reseller/InvitationsTest.php - tests/Browser/Reseller/LogonTest.php - tests/Browser/Reseller/PaymentMollieTest.php - tests/Browser/Reseller/ResourceTest.php - tests/Browser/Reseller/SharedFolderTest.php - tests/Browser/Reseller/StatsTest.php - tests/Browser/Reseller/UserTest.php - tests/Browser/Reseller/WalletTest.php - tests/Browser/Reseller/UserFinancesTest.php - tests/Browser/LogonTest.php - tests/Browser/SignupTest.php tests/Browser/PaymentStripeTest.php - tests/Browser/Meet/RoomSetupTest.php - tests/Browser/Meet/RoomControlsTest.php - tests/Browser/Meet/RoomModeratorTest.php diff --git a/src/resources/js/app.js b/src/resources/js/app.js --- a/src/resources/js/app.js +++ b/src/resources/js/app.js @@ -9,7 +9,6 @@ import AppComponent from '../vue/App' import MenuComponent from '../vue/Widgets/Menu' import SupportForm from '../vue/Widgets/SupportForm' -import { Tab } from 'bootstrap' import { loadLangAsync, i18n } from './locale' import { clearFormValidation, pick, startLoading, stopLoading } from './utils' @@ -169,10 +168,6 @@ pick, startLoading, stopLoading, - tab(e) { - e.preventDefault() - new Tab(e.target).show() - }, errorPage(code, msg, hint) { // Until https://github.com/vuejs/vue-router/issues/977 is implemented // we can't really use router to display error page as it has two side @@ -206,6 +201,10 @@ this.logoutUser(false) } } else { + if (!error.response) { + console.error(error) + } + this.errorPage(status, message) } }, diff --git a/src/resources/js/bootstrap.js b/src/resources/js/bootstrap.js --- a/src/resources/js/bootstrap.js +++ b/src/resources/js/bootstrap.js @@ -27,15 +27,17 @@ import VueRouter from 'vue-router' import Btn from '../vue/Widgets/Btn' import BtnRouter from '../vue/Widgets/BtnRouter' +import Tabs from '../vue/Widgets/Tabs' import Toast from '../vue/Widgets/Toast' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { Tooltip } from 'bootstrap' window.Vue = Vue -Vue.component('SvgIcon', FontAwesomeIcon) Vue.component('Btn', Btn) Vue.component('BtnRouter', BtnRouter) +Vue.component('SvgIcon', FontAwesomeIcon) +Vue.component('Tabs', Tabs) const vTooltip = (el, binding) => { let t = [] @@ -62,7 +64,6 @@ }) Vue.use(Toast) - Vue.use(VueRouter) let vueRouterBase = '/' diff --git a/src/resources/lang/en/ui.php b/src/resources/lang/en/ui.php --- a/src/resources/lang/en/ui.php +++ b/src/resources/lang/en/ui.php @@ -430,7 +430,6 @@ 'add-beta' => "Enable beta program", 'address' => "Address", 'aliases' => "Aliases", - 'aliases-email' => "Email Aliases", 'aliases-none' => "This user has no email aliases.", 'add-bonus' => "Add bonus", 'add-bonus-title' => "Add a bonus to the wallet", @@ -455,6 +454,7 @@ 'distlists' => "Distribution lists", 'domains' => "Domains", 'ext-email' => "External Email", + 'email-aliases' => "Email Aliases", 'finances' => "Finances", 'greylisting' => "Greylisting", 'greylisting-text' => "Greylisting is a method of defending users against spam. Any incoming mail from an unrecognized sender " diff --git a/src/resources/lang/fr/ui.php b/src/resources/lang/fr/ui.php --- a/src/resources/lang/fr/ui.php +++ b/src/resources/lang/fr/ui.php @@ -383,7 +383,6 @@ 'add-beta' => "Activer le programme bĂȘta", 'address' => "Adresse", 'aliases' => "Alias", - 'aliases-email' => "Alias E-mail", 'aliases-none' => "Cet utilisateur n'aucune alias e-mail.", 'add-bonus' => "Ajouter un bonus", 'add-bonus-title' => "Ajouter un bonus au portefeuille", @@ -406,6 +405,7 @@ 'discount-title' => "Rabais de compte", 'distlists' => "Listes de Distribution", 'domains' => "Domaines", + 'email-aliases' => "Alias E-mail", 'ext-email' => "E-mail externe", 'finances' => "Finances", 'greylisting' => "Greylisting", diff --git a/src/resources/vue/Admin/Distlist.vue b/src/resources/vue/Admin/Distlist.vue --- a/src/resources/vue/Admin/Distlist.vue +++ b/src/resources/vue/Admin/Distlist.vue @@ -47,15 +47,9 @@ - +
-
+
diff --git a/src/resources/vue/Admin/Domain.vue b/src/resources/vue/Admin/Domain.vue --- a/src/resources/vue/Admin/Domain.vue +++ b/src/resources/vue/Admin/Domain.vue @@ -35,20 +35,9 @@
- +
-
+

{{ $t('domain.dns-verify') }}

@@ -58,7 +47,7 @@
-
+
diff --git a/src/resources/vue/Admin/Resource.vue b/src/resources/vue/Admin/Resource.vue --- a/src/resources/vue/Admin/Resource.vue +++ b/src/resources/vue/Admin/Resource.vue @@ -31,15 +31,9 @@
- +
-
+
diff --git a/src/resources/vue/Admin/SharedFolder.vue b/src/resources/vue/Admin/SharedFolder.vue --- a/src/resources/vue/Admin/SharedFolder.vue +++ b/src/resources/vue/Admin/SharedFolder.vue @@ -37,20 +37,9 @@
- +
-
+
@@ -71,7 +60,7 @@
-
+
@@ -100,13 +89,18 @@ ], footLabel: 'shf.aliases-none' }, - folder: { config: {}, aliases: [] } + folder: { config: {}, aliases: [] }, + tabs: [ + { label: 'form.settings' }, + { label: 'user.email-aliases', count: 0 } + ] } }, created() { axios.get('/api/v4/shared-folders/' + this.$route.params.folder, { loader: true }) .then(response => { this.folder = response.data + this.tabs[1].count = this.folder.aliases.length }) .catch(this.$root.errorHandler) } diff --git a/src/resources/vue/Admin/User.vue b/src/resources/vue/Admin/User.vue --- a/src/resources/vue/Admin/User.vue +++ b/src/resources/vue/Admin/User.vue @@ -86,55 +86,9 @@
- +
-
+

{{ $t('wallet.title') }} @@ -181,14 +135,14 @@

-
+
-
+
@@ -203,42 +157,42 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -379,6 +333,17 @@ footLabel: 'user.subscriptions-none', model: 'sku' }, + tabs: [ + { label: 'user.finances' }, + { label: 'user.aliases', count: 0 }, + { label: 'user.subscriptions', count: 0 }, + { label: 'user.domains', count: 0 }, + { label: 'user.users', count: 0 }, + { label: 'user.distlists', count: 0 }, + { label: 'user.resources', count: 0 }, + { label: 'dashboard.shared-folders', count: 0 }, + { label: 'form.settings' } + ], users: [], user: { aliases: [], @@ -395,7 +360,7 @@ .then(response => { this.user = response.data - const loader = '#user-finances' + const loader = '#finances' const keys = ['first_name', 'last_name', 'external_email', 'billing_address', 'phone', 'organization'] let country = this.user.settings.country @@ -410,6 +375,8 @@ this.discount = this.user.wallet.discount this.discount_description = this.user.wallet.discount_description + this.$refs.tabs.updateCounter('aliases', this.user.aliases.length) + // TODO: currencies, multi-wallets, accounts // Get more info about the wallet (e.g. payment provider related) axios.get('/api/v4/wallets/' + this.user.wallets[0].id, { loader }) @@ -447,6 +414,8 @@ } } }) + + this.$refs.tabs.updateCounter('subscriptions', this.skus.length) }) // Fetch users @@ -454,37 +423,40 @@ axios.get('/api/v4/users?owner=' + user_id) .then(response => { this.users = response.data.list; + this.$refs.tabs.updateCounter('users', this.users.length) }) // Fetch domains axios.get('/api/v4/domains?owner=' + user_id) .then(response => { this.domains = response.data.list + this.$refs.tabs.updateCounter('domains', this.domains.length) }) // Fetch distribution lists axios.get('/api/v4/groups?owner=' + user_id) .then(response => { this.distlists = response.data.list + this.$refs.tabs.updateCounter('distlists', this.distlists.length) }) // Fetch resources lists axios.get('/api/v4/resources?owner=' + user_id) .then(response => { this.resources = response.data.list + this.$refs.tabs.updateCounter('resources', this.resources.length) }) // Fetch shared folders lists axios.get('/api/v4/shared-folders?owner=' + user_id) .then(response => { this.folders = response.data.list + this.$refs.tabs.updateCounter('folders', this.folders.length) }) }) .catch(this.$root.errorHandler) }, mounted() { - $(this.$el).find('ul.nav-tabs a').on('click', this.$root.tab) - this.$refs.discountDialog.events({ shown: () => { // Note: Vue v-model is strict, convert null to a string @@ -506,6 +478,8 @@ cost: sku.cost, price: this.$root.priceLabel(sku.cost, this.discount) }) + + this.$refs.tabs.updateCounter('subscriptions', this.skus.length) } }) }, @@ -561,6 +535,7 @@ this.$toast.success(response.data.message) this.skus = this.skus.filter(sku => sku.id != this.sku2FA) this.has2FA = false + this.$refs.tabs.updateCounter('subscriptions', this.skus.length) } }) }, diff --git a/src/resources/vue/CompanionApp.vue b/src/resources/vue/CompanionApp.vue --- a/src/resources/vue/CompanionApp.vue +++ b/src/resources/vue/CompanionApp.vue @@ -13,22 +13,9 @@
- - - +
-
+

@@ -40,13 +27,12 @@

-
+
-
diff --git a/src/resources/vue/Distlist/Info.vue b/src/resources/vue/Distlist/Info.vue --- a/src/resources/vue/Distlist/Info.vue +++ b/src/resources/vue/Distlist/Info.vue @@ -8,20 +8,9 @@ {{ $tc('distlist.list-title', 1) }} {{ $t('distlist.delete') }}
-
{{ $t('distlist.new') }}
+
{{ $t('distlist.new') }}
- +
diff --git a/src/resources/vue/Domain/Info.vue b/src/resources/vue/Domain/Info.vue --- a/src/resources/vue/Domain/Info.vue +++ b/src/resources/vue/Domain/Info.vue @@ -9,18 +9,7 @@ {{ $t('domain.delete') }}
- +
diff --git a/src/resources/vue/File/Info.vue b/src/resources/vue/File/Info.vue --- a/src/resources/vue/File/Info.vue +++ b/src/resources/vue/File/Info.vue @@ -7,18 +7,7 @@ {{ $t('file.delete') }}
- +
diff --git a/src/resources/vue/Resource/Info.vue b/src/resources/vue/Resource/Info.vue --- a/src/resources/vue/Resource/Info.vue +++ b/src/resources/vue/Resource/Info.vue @@ -10,18 +10,7 @@
{{ $t('resource.new') }}
- +
diff --git a/src/resources/vue/SharedFolder/Info.vue b/src/resources/vue/SharedFolder/Info.vue --- a/src/resources/vue/SharedFolder/Info.vue +++ b/src/resources/vue/SharedFolder/Info.vue @@ -10,18 +10,7 @@
{{ $t('shf.new') }}
- +
diff --git a/src/resources/vue/User/Info.vue b/src/resources/vue/User/Info.vue --- a/src/resources/vue/User/Info.vue +++ b/src/resources/vue/User/Info.vue @@ -11,18 +11,7 @@
{{ $t('user.new') }}
- +
@@ -57,7 +46,7 @@
- +
diff --git a/src/resources/vue/Wallet.vue b/src/resources/vue/Wallet.vue --- a/src/resources/vue/Wallet.vue +++ b/src/resources/vue/Wallet.vue @@ -41,25 +41,10 @@
- + +
-
+

@@ -77,12 +62,12 @@

-
+
-
+
@@ -213,6 +198,13 @@ } return [ button ] + }, + tabs() { + let tabs = [ 'wallet.receipts', 'wallet.history' ] + if (this.showPendingPayments) { + tabs.push('wallet.pending-payments') + } + return tabs } }, mounted() { @@ -224,7 +216,7 @@ .then(response => { this.wallet = response.data - axios.get('/api/v4/wallets/' + this.walletId + '/receipts', { loader: '#wallet-receipts' }) + axios.get('/api/v4/wallets/' + this.walletId + '/receipts', { loader: '#receipts' }) .then(response => { this.receipts = response.data.list }) @@ -241,17 +233,9 @@ .then(response => { this.showPendingPayments = response.data.hasPending }) - }, - updated() { - $(this.$el).find('ul.nav-tabs a').on('click', e => { - this.$root.tab(e) - - if ($(e.target).is('#tab-history')) { - this.loadTransactions = true - } else if ($(e.target).is('#tab-payments')) { - this.loadPayments = true - } - }) + + this.$refs.tabs.clickHandler('history', () => { this.loadTransactions = true }) + this.$refs.tabs.clickHandler('payments', () => { this.loadPayments = true }) }, methods: { loadMandate() { diff --git a/src/resources/vue/Widgets/Tabs.vue b/src/resources/vue/Widgets/Tabs.vue new file mode 100644 --- /dev/null +++ b/src/resources/vue/Widgets/Tabs.vue @@ -0,0 +1,65 @@ + + + diff --git a/src/tests/Browser/Admin/SharedFolderTest.php b/src/tests/Browser/Admin/SharedFolderTest.php --- a/src/tests/Browser/Admin/SharedFolderTest.php +++ b/src/tests/Browser/Admin/SharedFolderTest.php @@ -70,9 +70,9 @@ ->on(new Dashboard()) ->visit($user_page) ->on($user_page) - ->click('@nav #tab-shared-folders') + ->click('@nav #tab-folders') ->pause(1000) - ->click('@user-shared-folders table tbody tr:first-child td:first-child a') + ->click('@user-folders table tbody tr:first-child td:first-child a') ->on($folder_page) ->assertSeeIn('@folder-info .card-title', $folder->email) ->with('@folder-info form', function (Browser $browser) use ($folder) { diff --git a/src/tests/Browser/Admin/UserTest.php b/src/tests/Browser/Admin/UserTest.php --- a/src/tests/Browser/Admin/UserTest.php +++ b/src/tests/Browser/Admin/UserTest.php @@ -178,9 +178,9 @@ }); // Assert Shared folders tab - $browser->assertSeeIn('@nav #tab-shared-folders', 'Shared folders (0)') - ->click('@nav #tab-shared-folders') - ->with('@user-shared-folders', function (Browser $browser) { + $browser->assertSeeIn('@nav #tab-folders', 'Shared folders (0)') + ->click('@nav #tab-folders') + ->with('@user-folders', function (Browser $browser) { $browser->assertElementsCount('table tbody tr', 0) ->assertSeeIn('table tfoot tr td', 'There are no shared folders in this account.'); }); @@ -327,9 +327,9 @@ }); // Assert Shared folders tab - $browser->assertSeeIn('@nav #tab-shared-folders', 'Shared folders (2)') - ->click('@nav #tab-shared-folders') - ->with('@user-shared-folders', function (Browser $browser) { + $browser->assertSeeIn('@nav #tab-folders', 'Shared folders (2)') + ->click('@nav #tab-folders') + ->with('@user-folders', function (Browser $browser) { $browser->assertElementsCount('table tbody tr', 2) ->assertSeeIn('table tbody tr:nth-child(1) td:first-child', 'Calendar') ->assertSeeIn('table tbody tr:nth-child(1) td:nth-child(2)', 'Calendar') @@ -449,9 +449,9 @@ }); // We don't expect John's folders here - $browser->assertSeeIn('@nav #tab-shared-folders', 'Shared folders (0)') - ->click('@nav #tab-shared-folders') - ->with('@user-shared-folders', function (Browser $browser) { + $browser->assertSeeIn('@nav #tab-folders', 'Shared folders (0)') + ->click('@nav #tab-folders') + ->with('@user-folders', function (Browser $browser) { $browser->assertElementsCount('table tbody tr', 0) ->assertSeeIn('table tfoot tr td', 'There are no shared folders in this account.'); }); diff --git a/src/tests/Browser/Pages/Admin/Distlist.php b/src/tests/Browser/Pages/Admin/Distlist.php --- a/src/tests/Browser/Pages/Admin/Distlist.php +++ b/src/tests/Browser/Pages/Admin/Distlist.php @@ -51,7 +51,7 @@ return [ '@app' => '#app', '@distlist-info' => '#distlist-info', - '@distlist-settings' => '#distlist-settings', + '@distlist-settings' => '#settings', ]; } } diff --git a/src/tests/Browser/Pages/Admin/Domain.php b/src/tests/Browser/Pages/Admin/Domain.php --- a/src/tests/Browser/Pages/Admin/Domain.php +++ b/src/tests/Browser/Pages/Admin/Domain.php @@ -52,8 +52,8 @@ '@app' => '#app', '@domain-info' => '#domain-info', '@nav' => 'ul.nav-tabs', - '@domain-config' => '#domain-config', - '@domain-settings' => '#domain-settings', + '@domain-config' => '#config', + '@domain-settings' => '#settings', ]; } } diff --git a/src/tests/Browser/Pages/Admin/Resource.php b/src/tests/Browser/Pages/Admin/Resource.php --- a/src/tests/Browser/Pages/Admin/Resource.php +++ b/src/tests/Browser/Pages/Admin/Resource.php @@ -51,7 +51,7 @@ return [ '@app' => '#app', '@resource-info' => '#resource-info', - '@resource-settings' => '#resource-settings', + '@resource-settings' => '#settings', ]; } } diff --git a/src/tests/Browser/Pages/Admin/SharedFolder.php b/src/tests/Browser/Pages/Admin/SharedFolder.php --- a/src/tests/Browser/Pages/Admin/SharedFolder.php +++ b/src/tests/Browser/Pages/Admin/SharedFolder.php @@ -51,8 +51,8 @@ return [ '@app' => '#app', '@folder-info' => '#folder-info', - '@folder-settings' => '#folder-settings', - '@folder-aliases' => '#folder-aliases', + '@folder-settings' => '#settings', + '@folder-aliases' => '#aliases', ]; } } diff --git a/src/tests/Browser/Pages/Admin/User.php b/src/tests/Browser/Pages/Admin/User.php --- a/src/tests/Browser/Pages/Admin/User.php +++ b/src/tests/Browser/Pages/Admin/User.php @@ -53,15 +53,15 @@ '@app' => '#app', '@user-info' => '#user-info', '@nav' => 'ul.nav-tabs', - '@user-finances' => '#user-finances', - '@user-aliases' => '#user-aliases', - '@user-subscriptions' => '#user-subscriptions', - '@user-distlists' => '#user-distlists', - '@user-domains' => '#user-domains', - '@user-resources' => '#user-resources', - '@user-shared-folders' => '#user-shared-folders', - '@user-users' => '#user-users', - '@user-settings' => '#user-settings', + '@user-finances' => '#finances', + '@user-aliases' => '#aliases', + '@user-subscriptions' => '#subscriptions', + '@user-distlists' => '#distlists', + '@user-domains' => '#domains', + '@user-resources' => '#resources', + '@user-folders' => '#folders', + '@user-users' => '#users', + '@user-settings' => '#settings', ]; } } diff --git a/src/tests/Browser/Pages/Wallet.php b/src/tests/Browser/Pages/Wallet.php --- a/src/tests/Browser/Pages/Wallet.php +++ b/src/tests/Browser/Pages/Wallet.php @@ -42,8 +42,9 @@ '@main' => '#wallet', '@payment-dialog' => '#payment-dialog', '@nav' => 'ul.nav-tabs', - '@history-tab' => '#wallet-history', - '@receipts-tab' => '#wallet-receipts', + '@history-tab' => '#history', + '@receipts-tab' => '#receipts', + '@payments-tab' => '#payments', ]; } } diff --git a/src/tests/Browser/Reseller/PaymentMollieTest.php b/src/tests/Browser/Reseller/PaymentMollieTest.php --- a/src/tests/Browser/Reseller/PaymentMollieTest.php +++ b/src/tests/Browser/Reseller/PaymentMollieTest.php @@ -61,10 +61,10 @@ ->click('@main button') ->with(new Dialog('@payment-dialog'), function (Browser $browser) { $browser->assertSeeIn('@title', 'Top up your wallet') - ->waitFor('#payment-method-selection #creditcard') - ->waitFor('#payment-method-selection #paypal') - ->waitFor('#payment-method-selection #banktransfer') - ->click('#creditcard'); + ->waitFor('#payment-method-selection .link-creditcard svg') + ->waitFor('#payment-method-selection .link-paypal svg') + ->waitFor('#payment-method-selection .link-banktransfer svg') + ->click('#payment-method-selection .link-creditcard'); }) ->with(new Dialog('@payment-dialog'), function (Browser $browser) { $browser->assertSeeIn('@title', 'Top up your wallet') diff --git a/src/tests/Browser/Reseller/SharedFolderTest.php b/src/tests/Browser/Reseller/SharedFolderTest.php --- a/src/tests/Browser/Reseller/SharedFolderTest.php +++ b/src/tests/Browser/Reseller/SharedFolderTest.php @@ -70,9 +70,9 @@ ->on(new Dashboard()) ->visit($user_page) ->on($user_page) - ->click('@nav #tab-shared-folders') + ->click('@nav #tab-folders') ->pause(1000) - ->click('@user-shared-folders table tbody tr:first-child td:first-child a') + ->click('@user-folders table tbody tr:first-child td:first-child a') ->on($folder_page) ->assertSeeIn('@folder-info .card-title', $folder->email) ->with('@folder-info form', function (Browser $browser) use ($folder) { diff --git a/src/tests/Browser/Reseller/UserTest.php b/src/tests/Browser/Reseller/UserTest.php --- a/src/tests/Browser/Reseller/UserTest.php +++ b/src/tests/Browser/Reseller/UserTest.php @@ -175,9 +175,9 @@ }); // Assert Shared folders tab - $browser->assertSeeIn('@nav #tab-shared-folders', 'Shared folders (0)') - ->click('@nav #tab-shared-folders') - ->with('@user-shared-folders', function (Browser $browser) { + $browser->assertSeeIn('@nav #tab-folders', 'Shared folders (0)') + ->click('@nav #tab-folders') + ->with('@user-folders', function (Browser $browser) { $browser->assertElementsCount('table tbody tr', 0) ->assertSeeIn('table tfoot tr td', 'There are no shared folders in this account.'); }); @@ -323,9 +323,9 @@ }); // Assert Shared folders tab - $browser->assertSeeIn('@nav #tab-shared-folders', 'Shared folders (2)') - ->click('@nav #tab-shared-folders') - ->with('@user-shared-folders', function (Browser $browser) { + $browser->assertSeeIn('@nav #tab-folders', 'Shared folders (2)') + ->click('@nav #tab-folders') + ->with('@user-folders', function (Browser $browser) { $browser->assertElementsCount('table tbody tr', 2) ->assertSeeIn('table tbody tr:nth-child(1) td:first-child', 'Calendar') ->assertSeeIn('table tbody tr:nth-child(1) td:nth-child(2)', 'Calendar') @@ -422,9 +422,9 @@ }); // Assert Shared folders tab - $browser->assertSeeIn('@nav #tab-shared-folders', 'Shared folders (0)') - ->click('@nav #tab-shared-folders') - ->with('@user-shared-folders', function (Browser $browser) { + $browser->assertSeeIn('@nav #tab-folders', 'Shared folders (0)') + ->click('@nav #tab-folders') + ->with('@user-folders', function (Browser $browser) { $browser->assertElementsCount('table tbody tr', 0) ->assertSeeIn('table tfoot tr td', 'There are no shared folders in this account.'); });