Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117919006
D3557.1775421407.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
52 KB
Referenced Files
None
Subscribers
None
D3557.1775421407.diff
View Options
diff --git a/src/phpunit.xml b/src/phpunit.xml
--- a/src/phpunit.xml
+++ b/src/phpunit.xml
@@ -23,24 +23,7 @@
<testsuite name="Browser">
<directory suffix="Test.php">tests/Browser</directory>
- <exclude>tests/Browser/Reseller/DashboardTest.php</exclude>
- <exclude>tests/Browser/Reseller/DistlistTest.php</exclude>
- <exclude>tests/Browser/Reseller/DomainTest.php</exclude>
- <exclude>tests/Browser/Reseller/InvitationsTest.php</exclude>
- <exclude>tests/Browser/Reseller/LogonTest.php</exclude>
- <exclude>tests/Browser/Reseller/PaymentMollieTest.php</exclude>
- <exclude>tests/Browser/Reseller/ResourceTest.php</exclude>
- <exclude>tests/Browser/Reseller/SharedFolderTest.php</exclude>
- <exclude>tests/Browser/Reseller/StatsTest.php</exclude>
- <exclude>tests/Browser/Reseller/UserTest.php</exclude>
- <exclude>tests/Browser/Reseller/WalletTest.php</exclude>
- <exclude>tests/Browser/Reseller/UserFinancesTest.php</exclude>
- <exclude>tests/Browser/LogonTest.php</exclude>
- <exclude>tests/Browser/SignupTest.php</exclude>
<exclude>tests/Browser/PaymentStripeTest.php</exclude>
- <exclude>tests/Browser/Meet/RoomSetupTest.php</exclude>
- <exclude>tests/Browser/Meet/RoomControlsTest.php</exclude>
- <exclude>tests/Browser/Meet/RoomModeratorTest.php</exclude>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
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 @@
</div>
</div>
</div>
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-settings" href="#distlist-settings" role="tab" aria-controls="distlist-settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="['form.settings']"></tabs>
<div class="tab-content">
- <div class="tab-pane show active" id="distlist-settings" role="tabpanel" aria-labelledby="tab-settings">
+ <div class="tab-pane show active" id="settings" role="tabpanel" aria-labelledby="tab-settings">
<div class="card-body">
<div class="card-text">
<form class="read-only short">
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 @@
</div>
</div>
</div>
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-config" href="#domain-config" role="tab" aria-controls="domain-config" aria-selected="true" @click="$root.tab">
- {{ $t('form.config') }}
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-settings" href="#domain-settings" role="tab" aria-controls="domain-settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="['form.config', 'form.settings']"></tabs>
<div class="tab-content">
- <div class="tab-pane show active" id="domain-config" role="tabpanel" aria-labelledby="tab-config">
+ <div class="tab-pane show active" id="config" role="tabpanel" aria-labelledby="tab-config">
<div class="card-body">
<div class="card-text">
<p>{{ $t('domain.dns-verify') }}</p>
@@ -58,7 +47,7 @@
</div>
</div>
</div>
- <div class="tab-pane" id="domain-settings" role="tabpanel" aria-labelledby="tab-settings">
+ <div class="tab-pane" id="settings" role="tabpanel" aria-labelledby="tab-settings">
<div class="card-body">
<div class="card-text">
<form class="read-only short">
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 @@
</div>
</div>
</div>
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-settings" href="#resource-settings" role="tab" aria-controls="resource-settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="['form.settings']"></tabs>
<div class="tab-content">
- <div class="tab-pane show active" id="resource-settings" role="tabpanel" aria-labelledby="tab-settings">
+ <div class="tab-pane show active" id="settings" role="tabpanel" aria-labelledby="tab-settings">
<div class="card-body">
<div class="card-text">
<form class="read-only short">
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 @@
</div>
</div>
</div>
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-settings" href="#folder-settings" role="tab" aria-controls="folder-settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-aliases" href="#folder-aliases" role="tab" aria-controls="folder-aliases" aria-selected="false" @click="$root.tab">
- {{ $t('user.aliases-email') }} ({{ folder.aliases.length }})
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="tabs" ref="tabs"></tabs>
<div class="tab-content">
- <div class="tab-pane show active" id="folder-settings" role="tabpanel" aria-labelledby="tab-settings">
+ <div class="tab-pane show active" id="settings" role="tabpanel" aria-labelledby="tab-settings">
<div class="card-body">
<div class="card-text">
<form class="read-only short">
@@ -71,7 +60,7 @@
</div>
</div>
</div>
- <div class="tab-pane" id="folder-aliases" role="tabpanel" aria-labelledby="tab-aliases">
+ <div class="tab-pane" id="aliases" role="tabpanel" aria-labelledby="tab-aliases">
<div class="card-body">
<div class="card-text">
<list-table :list="folder.aliases" :setup="aliasesListSetup" class="mb-0"></list-table>
@@ -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 @@
</div>
</div>
</div>
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-finances" href="#user-finances" role="tab" aria-controls="user-finances" aria-selected="true">
- {{ $t('user.finances') }}
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-aliases" href="#user-aliases" role="tab" aria-controls="user-aliases" aria-selected="false">
- {{ $t('user.aliases') }} ({{ user.aliases.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-subscriptions" href="#user-subscriptions" role="tab" aria-controls="user-subscriptions" aria-selected="false">
- {{ $t('user.subscriptions') }} ({{ skus.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-domains" href="#user-domains" role="tab" aria-controls="user-domains" aria-selected="false">
- {{ $t('user.domains') }} ({{ domains.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-users" href="#user-users" role="tab" aria-controls="user-users" aria-selected="false">
- {{ $t('user.users') }} ({{ users.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-distlists" href="#user-distlists" role="tab" aria-controls="user-distlists" aria-selected="false">
- {{ $t('user.distlists') }} ({{ distlists.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-resources" href="#user-resources" role="tab" aria-controls="user-resources" aria-selected="false">
- {{ $t('user.resources') }} ({{ resources.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-shared-folders" href="#user-shared-folders" role="tab" aria-controls="user-shared-folders" aria-selected="false">
- {{ $t('dashboard.shared-folders') }} ({{ folders.length }})
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-settings" href="#user-settings" role="tab" aria-controls="user-settings" aria-selected="false">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="tabs" ref="tabs"></tabs>
<div class="tab-content">
- <div class="tab-pane show active" id="user-finances" role="tabpanel" aria-labelledby="tab-finances">
+ <div class="tab-pane show active" id="finances" role="tabpanel" aria-labelledby="tab-finances">
<div class="card-body">
<h2 class="card-title">
{{ $t('wallet.title') }}
@@ -181,14 +135,14 @@
<transaction-log v-if="wallet.id && !walletReload" class="card-text" :wallet-id="wallet.id" :is-admin="true"></transaction-log>
</div>
</div>
- <div class="tab-pane" id="user-aliases" role="tabpanel" aria-labelledby="tab-aliases">
+ <div class="tab-pane" id="aliases" role="tabpanel" aria-labelledby="tab-aliases">
<div class="card-body">
<div class="card-text">
<list-table :list="user.aliases" :setup="aliasesListSetup" class="mb-0"></list-table>
</div>
</div>
</div>
- <div class="tab-pane" id="user-subscriptions" role="tabpanel" aria-labelledby="tab-subscriptions">
+ <div class="tab-pane" id="subscriptions" role="tabpanel" aria-labelledby="tab-subscriptions">
<div class="card-body">
<div class="card-text">
<list-table :list="skus" :setup="skusListSetup" class="mb-0"></list-table>
@@ -203,42 +157,42 @@
</div>
</div>
</div>
- <div class="tab-pane" id="user-domains" role="tabpanel" aria-labelledby="tab-domains">
+ <div class="tab-pane" id="domains" role="tabpanel" aria-labelledby="tab-domains">
<div class="card-body">
<div class="card-text">
<domain-list :list="domains" class="mb-0"></domain-list>
</div>
</div>
</div>
- <div class="tab-pane" id="user-users" role="tabpanel" aria-labelledby="tab-users">
+ <div class="tab-pane" id="users" role="tabpanel" aria-labelledby="tab-users">
<div class="card-body">
<div class="card-text">
<user-list :list="users" :current="user" class="mb-0"></user-list>
</div>
</div>
</div>
- <div class="tab-pane" id="user-distlists" role="tabpanel" aria-labelledby="tab-distlists">
+ <div class="tab-pane" id="distlists" role="tabpanel" aria-labelledby="tab-distlists">
<div class="card-body">
<div class="card-text">
<distlist-list :list="distlists" class="mb-0"></distlist-list>
</div>
</div>
</div>
- <div class="tab-pane" id="user-resources" role="tabpanel" aria-labelledby="tab-resources">
+ <div class="tab-pane" id="resources" role="tabpanel" aria-labelledby="tab-resources">
<div class="card-body">
<div class="card-text">
<resource-list :list="resources" class="mb-0"></resource-list>
</div>
</div>
</div>
- <div class="tab-pane" id="user-shared-folders" role="tabpanel" aria-labelledby="tab-shared-folders">
+ <div class="tab-pane" id="folders" role="tabpanel" aria-labelledby="tab-folders">
<div class="card-body">
<div class="card-text">
<shared-folder-list :list="folders" :with-email="true" class="mb-0"></shared-folder-list>
</div>
</div>
</div>
- <div class="tab-pane" id="user-settings" role="tabpanel" aria-labelledby="tab-settings">
+ <div class="tab-pane" id="settings" role="tabpanel" aria-labelledby="tab-settings">
<div class="card-body">
<div class="card-text">
<form class="read-only short">
@@ -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 @@
</div>
</div>
</div>
-
- <ul class="nav nav-tabs mt-2" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-qrcode" href="#companion-qrcode" role="tab" aria-controls="companion-qrcode" aria-selected="true" @click="$root.tab">
- {{ $t('companion.pair-new') }}
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-list" href="#companion-list" role="tab" aria-controls="companion-list" aria-selected="false" @click="$root.tab">
- {{ $t('companion.paired') }}
- </a>
- </li>
- </ul>
-
+ <tabs class="mt-3" :tabs="['companion.pair-new','companion.paired']"></tabs>
<div class="tab-content">
- <div class="tab-pane active" id="companion-qrcode" role="tabpanel" aria-labelledby="tab-qrcode">
+ <div class="tab-pane active" id="new" role="tabpanel" aria-labelledby="tab-new">
<div class="card-body">
<div class="card-text">
<p>
@@ -40,13 +27,12 @@
</div>
</div>
</div>
- <div class="tab-pane" id="companion-list" role="tabpanel" aria-labelledby="tab-list">
+ <div class="tab-pane" id="paired" role="tabpanel" aria-labelledby="tab-paired">
<div class="card-body">
<companionapp-list class="card-text"></companionapp-list>
</div>
</div>
</div>
-
</div>
</template>
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) }}
<btn class="btn-outline-danger button-delete float-end" @click="deleteList()" icon="trash-can">{{ $t('distlist.delete') }}</btn>
</div>
- <div class="card-title" v-if="list_id === 'new'">{{ $t('distlist.new') }}</div>
+ <div class="card-title" v-else>{{ $t('distlist.new') }}</div>
<div class="card-text">
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-general" href="#general" role="tab" aria-controls="general" aria-selected="true" @click="$root.tab">
- {{ $t('form.general') }}
- </a>
- </li>
- <li v-if="list_id !== 'new'" class="nav-item">
- <a class="nav-link" id="tab-settings" href="#settings" role="tab" aria-controls="settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="list_id === 'new' ? ['form.general'] : ['form.general','form.settings']"></tabs>
<div class="tab-content">
<div class="tab-pane show active" id="general" role="tabpanel" aria-labelledby="tab-general">
<form @submit.prevent="submit" class="card-body">
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 @@
<btn class="btn-outline-danger button-delete float-end" @click="$refs.deleteDialog.show()" icon="trash-can">{{ $t('domain.delete') }}</btn>
</div>
<div class="card-text">
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-general" href="#general" role="tab" aria-controls="general" aria-selected="true" @click="$root.tab">
- {{ $t('form.general') }}
- </a>
- </li>
- <li class="nav-item" v-if="domain.id">
- <a class="nav-link" id="tab-settings" href="#settings" role="tab" aria-controls="settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="domain_id === 'new' ? ['form.general'] : ['form.general','form.settings']"></tabs>
<div class="tab-content">
<div class="tab-pane show active" id="general" role="tabpanel" aria-labelledby="tab-general">
<form @submit.prevent="submit" class="card-body">
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 @@
<btn v-if="file.canDelete" class="btn-outline-danger button-delete float-end" @click="fileDelete" icon="trash-can">{{ $t('file.delete') }}</btn>
</div>
<div class="card-text">
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-general" href="#general" role="tab" aria-controls="general" aria-selected="true" @click="$root.tab">
- {{ $t('form.general') }}
- </a>
- </li>
- <li class="nav-item" v-if="file.isOwner">
- <a class="nav-link" id="tab-sharing" href="#sharing" role="tab" aria-controls="sharing" aria-selected="false" @click="$root.tab">
- {{ $t('file.sharing') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="file.isOwner ? ['form.general','file.sharing'] : ['form.general']"></tabs>
<div class="tab-content">
<form class="tab-pane show active card-body read-only short" id="general" role="tabpanel" aria-labelledby="tab-general">
<div class="row plaintext">
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 @@
</div>
<div class="card-title" v-if="resource_id === 'new'">{{ $t('resource.new') }}</div>
<div class="card-text">
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-general" href="#general" role="tab" aria-controls="general" aria-selected="true" @click="$root.tab">
- {{ $t('form.general') }}
- </a>
- </li>
- <li v-if="resource_id !== 'new'" class="nav-item">
- <a class="nav-link" id="tab-settings" href="#settings" role="tab" aria-controls="settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="resource_id === 'new' ? ['form.general'] : ['form.general','form.settings']"></tabs>
<div class="tab-content">
<div class="tab-pane show active" id="general" role="tabpanel" aria-labelledby="tab-general">
<form @submit.prevent="submit" class="card-body">
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 @@
</div>
<div class="card-title" v-if="folder_id === 'new'">{{ $t('shf.new') }}</div>
<div class="card-text">
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-general" href="#general" role="tab" aria-controls="general" aria-selected="true" @click="$root.tab">
- {{ $t('form.general') }}
- </a>
- </li>
- <li v-if="folder_id !== 'new'" class="nav-item">
- <a class="nav-link" id="tab-settings" href="#settings" role="tab" aria-controls="settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="folder_id === 'new' ? ['form.general'] : ['form.general', 'form.settings']"></tabs>
<div class="tab-content">
<div class="tab-pane show active" id="general" role="tabpanel" aria-labelledby="tab-general">
<form @submit.prevent="submit" class="card-body">
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 @@
</div>
<div class="card-title" v-if="user_id === 'new'">{{ $t('user.new') }}</div>
<div class="card-text">
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-general" href="#general" role="tab" aria-controls="general" aria-selected="true" @click="$root.tab">
- {{ $t('form.general') }}
- </a>
- </li>
- <li v-if="user_id !== 'new'" class="nav-item">
- <a class="nav-link" id="tab-settings" href="#settings" role="tab" aria-controls="settings" aria-selected="false" @click="$root.tab">
- {{ $t('form.settings') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" :tabs="user_id === 'new' ? ['form.general'] : ['form.general','form.settings']"></tabs>
<div class="tab-content">
<div class="tab-pane show active" id="general" role="tabpanel" aria-labelledby="tab-general">
<form @submit.prevent="submit" class="card-body">
@@ -57,7 +46,7 @@
</div>
</div>
<div class="row mb-3">
- <label for="aliases-input" class="col-sm-4 col-form-label">{{ $t('user.aliases-email') }}</label>
+ <label for="aliases-input" class="col-sm-4 col-form-label">{{ $t('user.email-aliases') }}</label>
<div class="col-sm-8">
<list-input id="aliases" :list="user.aliases"></list-input>
</div>
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 @@
</div>
</div>
- <ul class="nav nav-tabs mt-3" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" id="tab-receipts" href="#wallet-receipts" role="tab" aria-controls="wallet-receipts" aria-selected="true">
- {{ $t('wallet.receipts') }}
- </a>
- </li>
- <li class="nav-item">
- <a class="nav-link" id="tab-history" href="#wallet-history" role="tab" aria-controls="wallet-history" aria-selected="false">
- {{ $t('wallet.history') }}
- </a>
- </li>
- <li v-if="showPendingPayments" class="nav-item">
- <a class="nav-link" id="tab-payments" href="#wallet-payments" role="tab" aria-controls="wallet-payments" aria-selected="false">
- {{ $t('wallet.pending-payments') }}
- </a>
- </li>
- </ul>
+ <tabs class="mt-3" ref="tabs" :tabs="tabs"></tabs>
+
<div class="tab-content">
- <div class="tab-pane active" id="wallet-receipts" role="tabpanel" aria-labelledby="tab-receipts">
+ <div class="tab-pane active" id="receipts" role="tabpanel" aria-labelledby="tab-receipts">
<div class="card-body">
<div class="card-text">
<p v-if="receipts.length">
@@ -77,12 +62,12 @@
</div>
</div>
</div>
- <div class="tab-pane" id="wallet-history" role="tabpanel" aria-labelledby="tab-history">
+ <div class="tab-pane" id="history" role="tabpanel" aria-labelledby="tab-history">
<div class="card-body">
<transaction-log v-if="walletId && loadTransactions" class="card-text" :wallet-id="walletId"></transaction-log>
</div>
</div>
- <div class="tab-pane" id="wallet-payments" role="tabpanel" aria-labelledby="tab-payments">
+ <div class="tab-pane" id="payments" role="tabpanel" aria-labelledby="tab-payments">
<div class="card-body">
<payment-log v-if="walletId && loadPayments" class="card-text" :wallet-id="walletId"></payment-log>
</div>
@@ -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 @@
+<template>
+ <ul class="nav nav-tabs" role="tablist">
+ <li v-for="(tab, index) in tabs" :key="index" class="nav-item">
+ <a role="tab" :aria-controls="tabKey(tab)" :aria-selected="!index" @click="tabClick"
+ :class="'nav-link' + (!index ? ' active' : '')"
+ :id="'tab-' + tabKey(tab)"
+ :href="'#' + tabKey(tab)"
+ >
+ {{ $t(tabLabel(tab)) + (typeof tab != 'string' && 'count' in tab ? ` (${tab.count})` : '') }}
+ </a>
+ </li>
+ </ul>
+</template>
+
+<script>
+ import { Tab } from 'bootstrap'
+
+ export default {
+ props: {
+ tabs: { type: Array, default: () => [] }
+ },
+ data() {
+ return {
+ clickHandlers: {}
+ }
+ },
+ methods: {
+ tabClick(event) {
+ event.preventDefault()
+
+ new Tab(event.target).show()
+
+ const key = event.target.id.replace('tab-', '')
+
+ if (key in this.clickHandlers) {
+ this.clickHandlers[key](event)
+ }
+ },
+ tabKey(tab) {
+ return this.tabLabel(tab).split(/[.-]/).slice(-1)
+ },
+ tabIndex(key) {
+ return this.tabs.findIndex(tab => this.tabKey(tab) == key)
+ },
+ tabLabel(tab) {
+ return typeof tab == 'string' ? tab : tab.label
+ },
+ updateCounter(key, count) {
+ const index = this.tabIndex(key)
+ let tab = this.tabs[index]
+
+ if (typeof tab == 'string') {
+ tab = { label: tab, count }
+ } else {
+ tab.count = count
+ }
+
+ this.$set(this.tabs, index, tab)
+ },
+ clickHandler(key, callback) {
+ this.clickHandlers[key] = callback
+ }
+ }
+ }
+</script>
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.');
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 5, 8:36 PM (7 h, 19 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18818775
Default Alt Text
D3557.1775421407.diff (52 KB)
Attached To
Mode
D3557: Tabs widget
Attached
Detach File
Event Timeline