Page MenuHomePhorge

D3544.1775500262.diff
No OneTemporary

Authored By
Unknown
Size
47 KB
Referenced Files
None
Subscribers
None

D3544.1775500262.diff

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
@@ -47,7 +47,7 @@
'paired' => "Paired devices",
'pairing-instructions' => "Pair a new device using the following QR-Code:",
'deviceid' => "Device ID",
- 'nodevices' => "There are currently no devices",
+ 'list-empty' => "There are currently no devices",
'delete' => "Remove devices",
'remove-devices' => "Remove Devices",
'remove-devices-text' => "Do you really want to remove all devices permanently?"
@@ -96,6 +96,7 @@
. " Please note that this action cannot be undone.",
'dns-verify' => "Domain DNS verification sample:",
'dns-config' => "Domain DNS configuration sample:",
+ 'list-empty' => "There are no domains in this account.",
'namespace' => "Namespace",
'spf-whitelist' => "SPF Whitelist",
'spf-whitelist-text' => "The Sender Policy Framework allows a sender domain to disclose, through DNS, "
@@ -186,7 +187,7 @@
'create-title' => "Invite for a signup",
'create-email' => "Enter an email address of the person you want to invite.",
'create-csv' => "To send multiple invitations at once, provide a CSV (comma separated) file, or alternatively a plain-text file, containing one email address per line.",
- 'empty-list' => "There are no invitations in the database.",
+ 'list-empty' => "There are no invitations in the database.",
'title' => "Signup invitations",
'search' => "Email address or domain",
'send' => "Send invite(s)",
@@ -453,7 +454,6 @@
'discount-title' => "Account discount",
'distlists' => "Distribution lists",
'domains' => "Domains",
- 'domains-none' => "There are no domains in this account.",
'ext-email' => "External Email",
'finances' => "Finances",
'greylisting' => "Greylisting",
@@ -461,6 +461,7 @@
. "is temporarily rejected. The originating server should try again after a delay. "
. "This time the email will be accepted. Spammers usually do not reattempt mail delivery.",
'list-title' => "User accounts",
+ 'list-empty' => "There are no users in this account.",
'managed-by' => "Managed by",
'new' => "New user account",
'org' => "Organization",
@@ -492,7 +493,6 @@
'subscriptions' => "Subscriptions",
'subscriptions-none' => "This user has no subscriptions.",
'users' => "Users",
- 'users-none' => "There are no users in this account.",
],
'wallet' => [
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
@@ -70,6 +70,7 @@
'domain' => [
'dns-verify' => "Exemple de vérification du DNS d'un domaine:",
'dns-config' => "Exemple de configuration du DNS d'un domaine:",
+ 'list-empty' => "Il y a pas de domaines dans ce compte.",
'namespace' => "Espace de noms",
'verify' => "Vérification du domaine",
'verify-intro' => "Afin de confirmer que vous êtes bien le titulaire du domaine, nous devons exécuter un processus de vérification avant de l'activer définitivement pour la livraison d'e-mails.",
@@ -148,7 +149,7 @@
'create-title' => "Invitation à une inscription",
'create-email' => "Saisissez l'adresse électronique de la personne que vous souhaitez inviter.",
'create-csv' => "Pour envoyer plusieurs invitations à la fois, fournissez un fichier CSV (séparé par des virgules) ou un fichier en texte brut, contenant une adresse e-mail par ligne.",
- 'empty-list' => "Il y a aucune invitation dans la mémoire de données.",
+ 'list-empty' => "Il y a aucune invitation dans la mémoire de données.",
'title' => "Invitation d'inscription",
'search' => "Adresse E-mail ou domaine",
'send' => "Envoyer invitation(s)",
@@ -405,7 +406,6 @@
'discount-title' => "Rabais de compte",
'distlists' => "Listes de Distribution",
'domains' => "Domaines",
- 'domains-none' => "Il y a pas de domaines dans ce compte.",
'ext-email' => "E-mail externe",
'finances' => "Finances",
'greylisting' => "Greylisting",
@@ -414,6 +414,7 @@
. " Le serveur d'origine doit réessayer après un délai cette fois-ci, le mail sera accepté."
. " Les spammeurs ne réessayent généralement pas de remettre le mail.",
'list-title' => "Comptes d'utilisateur",
+ 'list-empty' => "Il n'y a aucun utilisateur dans ce compte.",
'managed-by' => "Géré par",
'new' => "Nouveau compte d'utilisateur",
'org' => "Organisation",
@@ -440,7 +441,6 @@
'subscriptions' => "Subscriptions",
'subscriptions-none' => "Cet utilisateur n'a pas de subscriptions.",
'users' => "Utilisateurs",
- 'users-none' => "Il n'y a aucun utilisateur dans ce compte.",
],
'wallet' => [
diff --git a/src/resources/themes/app.scss b/src/resources/themes/app.scss
--- a/src/resources/themes/app.scss
+++ b/src/resources/themes/app.scss
@@ -170,13 +170,6 @@
padding: 0;
}
- td {
- & > svg + a,
- & > svg + span {
- margin-left: .4em;
- }
- }
-
&.files {
table-layout: fixed;
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
@@ -74,23 +74,7 @@
<div class="tab-pane" id="folder-aliases" role="tabpanel" aria-labelledby="tab-aliases">
<div class="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="(alias, index) in folder.aliases" :id="'alias' + index" :key="index">
- <td>{{ alias }}</td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td>{{ $t('shf.aliases-none') }}</td>
- </tr>
- </tfoot>
- </table>
+ <list-table :list="folder.aliases" :setup="aliasesListSetup" class="mb-0"></list-table>
</div>
</div>
</div>
@@ -99,9 +83,23 @@
</template>
<script>
+ import { ListTable } from '../Widgets/ListTools'
+
export default {
+ components: {
+ ListTable
+ },
data() {
return {
+ aliasesListSetup: {
+ columns: [
+ {
+ prop: 'email',
+ content: item => item
+ },
+ ],
+ footLabel: 'shf.aliases-none'
+ },
folder: { config: {}, aliases: [] }
}
},
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
@@ -184,48 +184,14 @@
<div class="tab-pane" id="user-aliases" role="tabpanel" aria-labelledby="tab-aliases">
<div class="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="(alias, index) in user.aliases" :id="'alias' + index" :key="index">
- <td>{{ alias }}</td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td>{{ $t('user.aliases-none') }}</td>
- </tr>
- </tfoot>
- </table>
+ <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="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('user.subscription') }}</th>
- <th scope="col">{{ $t('user.price') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="(sku, sku_id) in skus" :id="'sku' + sku.id" :key="sku_id">
- <td>{{ sku.name }}</td>
- <td class="price">{{ sku.price }}</td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="2">{{ $t('user.subscriptions-none') }}</td>
- </tr>
- </tfoot>
- </table>
+ <list-table :list="skus" :setup="skusListSetup" class="mb-0"></list-table>
<small v-if="discount > 0" class="hint">
<hr class="m-0">
&sup1; {{ $t('user.discount-hint') }}: {{ discount }}% - {{ discount_description }}
@@ -240,143 +206,35 @@
<div class="tab-pane" id="user-domains" role="tabpanel" aria-labelledby="tab-domains">
<div class="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('domain.namespace') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="domain in domains" :id="'domain' + domain.id" :key="domain.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="globe" :class="$root.statusClass(domain)" :title="$root.statusText(domain)"></svg-icon>
- <router-link :to="{ path: '/domain/' + domain.id }">{{ domain.namespace }}</router-link>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td>{{ $t('user.domains-none') }}</td>
- </tr>
- </tfoot>
- </table>
+ <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="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.primary-email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="item in users" :id="'user' + item.id" :key="item.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="user" :class="$root.statusClass(item)" :title="$root.statusText(item)"></svg-icon>
- <router-link v-if="item.id != user.id" :to="{ path: '/user/' + item.id }">{{ item.email }}</router-link>
- <span v-else>{{ item.email }}</span>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td>{{ $t('user.users-none') }}</td>
- </tr>
- </tfoot>
- </table>
+ <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="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('distlist.name') }}</th>
- <th scope="col">{{ $t('form.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="list in distlists" :key="list.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="users" :class="$root.statusClass(list)" :title="$root.statusText(list)"></svg-icon>
- <router-link :to="{ path: '/distlist/' + list.id }">{{ list.name }}</router-link>
- </td>
- <td>
- <router-link :to="{ path: '/distlist/' + list.id }">{{ list.email }}</router-link>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="2">{{ $t('distlist.list-empty') }}</td>
- </tr>
- </tfoot>
- </table>
+ <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="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.name') }}</th>
- <th scope="col">{{ $t('form.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="resource in resources" :key="resource.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="gear" :class="$root.statusClass(resource)" :title="$root.statusText(resource)"></svg-icon>
- <router-link :to="{ path: '/resource/' + resource.id }">{{ resource.name }}</router-link>
- </td>
- <td>
- <router-link :to="{ path: '/resource/' + resource.id }">{{ resource.email }}</router-link>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="2">{{ $t('resource.list-empty') }}</td>
- </tr>
- </tfoot>
- </table>
+ <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="card-body">
<div class="card-text">
- <table class="table table-sm table-hover mb-0">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.name') }}</th>
- <th scope="col">{{ $t('form.type') }}</th>
- <th scope="col">{{ $t('form.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="folder in folders" :key="folder.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="folder-open" :class="$root.statusClass(folder)" :title="$root.statusText(folder)"></svg-icon>
- <router-link :to="{ path: '/shared-folder/' + folder.id }">{{ folder.name }}</router-link>
- </td>
- <td>{{ $t('shf.type-' + folder.type) }}</td>
- <td><router-link :to="{ path: '/shared-folder/' + folder.id }">{{ folder.email }}</router-link></td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="3">{{ $t('shf.list-empty') }}</td>
- </tr>
- </tfoot>
- </table>
+ <shared-folder-list :list="folders" :with-email="true" class="mb-0"></shared-folder-list>
</div>
</div>
</div>
@@ -496,6 +354,12 @@
<script>
import { Modal } from 'bootstrap'
import TransactionLog from '../Widgets/TransactionLog'
+ import { ListTable } from '../Widgets/ListTools'
+ import { default as DistlistList } from '../Distlist/ListWidget'
+ import { default as DomainList } from '../Domain/ListWidget'
+ import { default as ResourceList } from '../Resource/ListWidget'
+ import { default as SharedFolderList } from '../SharedFolder/ListWidget'
+ import { default as UserList } from '../User/ListWidget'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -508,7 +372,13 @@
export default {
components: {
- TransactionLog
+ DistlistList,
+ DomainList,
+ ListTable,
+ ResourceList,
+ SharedFolderList,
+ TransactionLog,
+ UserList
},
beforeRouteUpdate (to, from, next) {
// An event called when the route that renders this component has changed,
@@ -519,6 +389,15 @@
},
data() {
return {
+ aliasesListSetup: {
+ columns: [
+ {
+ prop: 'email',
+ content: item => item
+ },
+ ],
+ footLabel: 'user.aliases-none'
+ },
oneoff_amount: '',
oneoff_description: '',
oneoff_negative: false,
@@ -534,8 +413,23 @@
distlists: [],
domains: [],
resources: [],
- skus: [],
sku2FA: null,
+ skus: [],
+ skusListSetup: {
+ columns: [
+ {
+ prop: 'name',
+ label: 'user.subscription'
+ },
+ {
+ prop: 'price',
+ className: 'price',
+ label: 'user.price'
+ }
+ ],
+ footLabel: 'user.subscriptions-none',
+ model: 'sku'
+ },
users: [],
user: {
aliases: [],
diff --git a/src/resources/vue/Distlist/List.vue b/src/resources/vue/Distlist/List.vue
--- a/src/resources/vue/Distlist/List.vue
+++ b/src/resources/vue/Distlist/List.vue
@@ -10,30 +10,7 @@
</btn-router>
</div>
<div class="card-text">
- <table class="table table-sm table-hover">
- <thead>
- <tr>
- <th scope="col">{{ $t('distlist.name') }}</th>
- <th scope="col">{{ $t('distlist.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="list in lists" :key="list.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="users" :class="$root.statusClass(list)" :title="$root.statusText(list)"></svg-icon>
- <router-link :to="{ path: 'distlist/' + list.id }">{{ list.name }}</router-link>
- </td>
- <td>
- <router-link :to="{ path: 'distlist/' + list.id }">{{ list.email }}</router-link>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="2">{{ $t('distlist.list-empty') }}</td>
- </tr>
- </tfoot>
- </table>
+ <list-widget :list="lists"></list-widget>
</div>
</div>
</div>
@@ -41,6 +18,7 @@
</template>
<script>
+ import ListWidget from './ListWidget'
import { library } from '@fortawesome/fontawesome-svg-core'
library.add(
@@ -48,6 +26,9 @@
)
export default {
+ components: {
+ ListWidget
+ },
data() {
return {
lists: []
diff --git a/src/resources/vue/Distlist/ListWidget.vue b/src/resources/vue/Distlist/ListWidget.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/Distlist/ListWidget.vue
@@ -0,0 +1,39 @@
+<template>
+ <list-table :list="list" :setup="setup"></list-table>
+</template>
+
+<script>
+ import { ListTable } from '../Widgets/ListTools'
+ import { library } from '@fortawesome/fontawesome-svg-core'
+
+ library.add(
+ require('@fortawesome/free-solid-svg-icons/faUsers').definition,
+ )
+
+ export default {
+ components: {
+ ListTable
+ },
+ props: {
+ list: { type: Array, default: () => [] }
+ },
+ data() {
+ return {
+ setup: {
+ model: 'distlist',
+ columns: [
+ {
+ prop: 'name',
+ icon: 'users',
+ link: true
+ },
+ {
+ prop: 'email',
+ link: true
+ }
+ ]
+ }
+ }
+ }
+ }
+</script>
diff --git a/src/resources/vue/Domain/List.vue b/src/resources/vue/Domain/List.vue
--- a/src/resources/vue/Domain/List.vue
+++ b/src/resources/vue/Domain/List.vue
@@ -9,26 +9,7 @@
</btn-router>
</div>
<div class="card-text">
- <table class="table table-sm table-hover">
- <thead>
- <tr>
- <th scope="col">{{ $t('domain.namespace') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="domain in domains" :key="domain.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="globe" :class="$root.statusClass(domain)" :title="$root.statusText(domain)"></svg-icon>
- <router-link :to="{ path: 'domain/' + domain.id }">{{ domain.namespace }}</router-link>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td>{{ $t('user.domains-none') }}</td>
- </tr>
- </tfoot>
- </table>
+ <list-widget :list="domains"></list-widget>
</div>
</div>
</div>
@@ -36,6 +17,7 @@
</template>
<script>
+ import ListWidget from './ListWidget'
import { library } from '@fortawesome/fontawesome-svg-core'
library.add(
@@ -43,6 +25,9 @@
)
export default {
+ components: {
+ ListWidget
+ },
data() {
return {
domains: []
diff --git a/src/resources/vue/Domain/ListWidget.vue b/src/resources/vue/Domain/ListWidget.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/Domain/ListWidget.vue
@@ -0,0 +1,35 @@
+<template>
+ <list-table :list="list" :setup="setup"></list-table>
+</template>
+
+<script>
+ import { ListTable } from '../Widgets/ListTools'
+ import { library } from '@fortawesome/fontawesome-svg-core'
+
+ library.add(
+ require('@fortawesome/free-solid-svg-icons/faGlobe').definition,
+ )
+
+ export default {
+ components: {
+ ListTable
+ },
+ props: {
+ list: { type: Array, default: () => [] }
+ },
+ data() {
+ return {
+ setup: {
+ model: 'domain',
+ columns: [
+ {
+ prop: 'namespace',
+ icon: 'globe',
+ link: true
+ }
+ ]
+ }
+ }
+ }
+ }
+</script>
diff --git a/src/resources/vue/Reseller/Invitations.vue b/src/resources/vue/Reseller/Invitations.vue
--- a/src/resources/vue/Reseller/Invitations.vue
+++ b/src/resources/vue/Reseller/Invitations.vue
@@ -11,35 +11,20 @@
<btn class="btn-success create-invite ms-1" @click="inviteUserDialog" icon="envelope-open-text">{{ $t('invitation.create') }}</btn>
</div>
- <table id="invitations-list" class="table table-sm table-hover">
- <thead>
- <tr>
- <th scope="col">{{ $t('user.ext-email') }}</th>
- <th scope="col">{{ $t('form.created') }}</th>
- <th scope="col"></th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="inv in invitations" :id="'i' + inv.id" :key="inv.id">
- <td class="email">
- <svg-icon icon="envelope-open-text" :class="statusClass(inv)" :title="$t('invitation.status-' + statusLabel(inv))"></svg-icon>
- <span>{{ inv.email }}</span>
- </td>
- <td class="datetime">
- {{ inv.created }}
- </td>
- <td class="buttons">
- <btn class="text-danger button-delete p-0 ms-1" @click="deleteInvite(inv.id)" icon="trash-can">
- <span class="btn-label">{{ $t('btn.delete') }}</span>
- </btn>
- <btn class="button-resend p-0 ms-1" :disabled="inv.isNew || inv.isCompleted" @click="resendInvite(inv.id)" icon="redo">
- <span class="btn-label">{{ $t('btn.resend') }}</span>
- </btn>
- </td>
- </tr>
- </tbody>
- <list-foot :text="$t('invitation.empty-list')" colspan="3"></list-foot>
- </table>
+ <list-table id="invitations-list" :list="invitations" :setup="setup">
+ <template #email="{ item }">
+ <svg-icon icon="envelope-open-text" :class="statusClass(item)" :title="$t('invitation.status-' + statusLabel(item))"></svg-icon>
+ &nbsp;<span>{{ item.email }}</span>
+ </template>
+ <template #buttons="{ item }">
+ <btn class="text-danger button-delete p-0 ms-1" @click="deleteInvite(item.id)" icon="trash-can">
+ <span class="btn-label">{{ $t('btn.delete') }}</span>
+ </btn>
+ <btn class="button-resend p-0 ms-1" :disabled="item.isNew || item.isCompleted" @click="resendInvite(item.id)" icon="rotate-left">
+ <span class="btn-label">{{ $t('btn.resend') }}</span>
+ </btn>
+ </template>
+ </list-table>
<list-more v-if="hasMore" :on-click="loadInvitations"></list-more>
</div>
</div>
@@ -84,14 +69,30 @@
library.add(
require('@fortawesome/free-solid-svg-icons/faEnvelopeOpenText').definition,
require('@fortawesome/free-solid-svg-icons/faPaperPlane').definition,
- require('@fortawesome/free-solid-svg-icons/faRedo').definition,
+ require('@fortawesome/free-solid-svg-icons/faRotateLeft').definition,
)
export default {
mixins: [ ListTools ],
data() {
return {
- invitations: []
+ invitations: [],
+ setup: {
+ buttons: true,
+ model: 'invitation',
+ columns: [
+ {
+ prop: 'email',
+ label: 'user.ext-email',
+ className: 'email',
+ contentSlot: 'email'
+ },
+ {
+ prop: 'created',
+ className: 'datetime'
+ }
+ ]
+ }
}
},
mounted() {
diff --git a/src/resources/vue/Resource/List.vue b/src/resources/vue/Resource/List.vue
--- a/src/resources/vue/Resource/List.vue
+++ b/src/resources/vue/Resource/List.vue
@@ -10,30 +10,7 @@
</btn-router>
</div>
<div class="card-text">
- <table class="table table-sm table-hover">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.name') }}</th>
- <th scope="col">{{ $t('form.email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="resource in resources" :key="resource.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="gear" :class="$root.statusClass(resource)" :title="$root.statusText(resource)"></svg-icon>
- <router-link :to="{ path: 'resource/' + resource.id }">{{ resource.name }}</router-link>
- </td>
- <td>
- <router-link :to="{ path: 'resource/' + resource.id }">{{ resource.email }}</router-link>
- </td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="2">{{ $t('resource.list-empty') }}</td>
- </tr>
- </tfoot>
- </table>
+ <list-widget :list="resources"></list-widget>
</div>
</div>
</div>
@@ -41,6 +18,7 @@
</template>
<script>
+ import ListWidget from './ListWidget'
import { library } from '@fortawesome/fontawesome-svg-core'
library.add(
@@ -48,6 +26,9 @@
)
export default {
+ components: {
+ ListWidget
+ },
data() {
return {
resources: []
diff --git a/src/resources/vue/Resource/ListWidget.vue b/src/resources/vue/Resource/ListWidget.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/Resource/ListWidget.vue
@@ -0,0 +1,39 @@
+<template>
+ <list-table :list="list" :setup="setup"></list-table>
+</template>
+
+<script>
+ import { ListTable } from '../Widgets/ListTools'
+ import { library } from '@fortawesome/fontawesome-svg-core'
+
+ library.add(
+ require('@fortawesome/free-solid-svg-icons/faGear').definition,
+ )
+
+ export default {
+ components: {
+ ListTable
+ },
+ props: {
+ list: { type: Array, default: () => [] }
+ },
+ data() {
+ return {
+ setup: {
+ model: 'resource',
+ columns: [
+ {
+ prop: 'name',
+ icon: 'gear',
+ link: true
+ },
+ {
+ prop: 'email',
+ link: true
+ }
+ ]
+ }
+ }
+ }
+ }
+</script>
diff --git a/src/resources/vue/SharedFolder/List.vue b/src/resources/vue/SharedFolder/List.vue
--- a/src/resources/vue/SharedFolder/List.vue
+++ b/src/resources/vue/SharedFolder/List.vue
@@ -5,33 +5,12 @@
<div class="card-title">
{{ $tc('shf.list-title', 2) }}
<small><sup class="badge bg-primary">{{ $t('dashboard.beta') }}</sup></small>
- <btn-router v-if="!$root.isDegraded()" to="shared-folder/new" class="btn-success float-end" icon="gear">
+ <btn-router v-if="!$root.isDegraded()" to="shared-folder/new" class="btn-success float-end" icon="folder-open">
{{ $t('shf.create') }}
</btn-router>
</div>
<div class="card-text">
- <table class="table table-sm table-hover">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.name') }}</th>
- <th scope="col">{{ $t('form.type') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="folder in folders" :key="folder.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="folder-open" :class="$root.statusClass(folder)" :title="$root.statusText(folder)"></svg-icon>
- <router-link :to="{ path: 'shared-folder/' + folder.id }">{{ folder.name }}</router-link>
- </td>
- <td>{{ $t('shf.type-' + folder.type) }}</td>
- </tr>
- </tbody>
- <tfoot class="table-fake-body">
- <tr>
- <td colspan="2">{{ $t('shf.list-empty') }}</td>
- </tr>
- </tfoot>
- </table>
+ <list-widget :list="folders"></list-widget>
</div>
</div>
</div>
@@ -39,14 +18,17 @@
</template>
<script>
+ import ListWidget from './ListWidget'
import { library } from '@fortawesome/fontawesome-svg-core'
library.add(
require('@fortawesome/free-solid-svg-icons/faFolderOpen').definition,
- require('@fortawesome/free-solid-svg-icons/faGear').definition,
)
export default {
+ components: {
+ ListWidget
+ },
data() {
return {
folders: []
diff --git a/src/resources/vue/SharedFolder/ListWidget.vue b/src/resources/vue/SharedFolder/ListWidget.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/SharedFolder/ListWidget.vue
@@ -0,0 +1,47 @@
+<template>
+ <list-table :list="list" :setup="setup"></list-table>
+</template>
+
+<script>
+ import { ListTable } from '../Widgets/ListTools'
+ import { library } from '@fortawesome/fontawesome-svg-core'
+
+ library.add(
+ require('@fortawesome/free-solid-svg-icons/faFolderOpen').definition,
+ )
+
+ export default {
+ components: {
+ ListTable
+ },
+ props: {
+ withEmail: { type: Boolean, default: () => false },
+ list: { type: Array, default: () => [] }
+ },
+ computed: {
+ setup() {
+ let columns = [
+ {
+ prop: 'name',
+ icon: 'folder-open',
+ link: true
+ },
+ {
+ prop: 'type',
+ contentLabel: item => 'shf.type-' + item.type
+ }
+ ]
+
+ if (this.withEmail) {
+ columns.push({ prop: 'email', link: true })
+ }
+
+ return {
+ columns,
+ model: 'shared-folder',
+ prefix: 'shf'
+ }
+ }
+ }
+ }
+</script>
diff --git a/src/resources/vue/User/List.vue b/src/resources/vue/User/List.vue
--- a/src/resources/vue/User/List.vue
+++ b/src/resources/vue/User/List.vue
@@ -12,22 +12,7 @@
{{ $t('user.create') }}
</btn-router>
</div>
- <table id="users-list" class="table table-sm table-hover">
- <thead>
- <tr>
- <th scope="col">{{ $t('form.primary-email') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="user in users" :id="'user' + user.id" :key="user.id" @click="$root.clickRecord">
- <td>
- <svg-icon icon="user" :class="$root.statusClass(user)" :title="$root.statusText(user)"></svg-icon>
- <router-link :to="{ path: 'user/' + user.id }">{{ user.email }}</router-link>
- </td>
- </tr>
- </tbody>
- <list-foot :text="$t('user.users-none')"></list-foot>
- </table>
+ <list-widget :list="users"></list-widget>
<list-more v-if="hasMore" :on-click="loadUsers"></list-more>
</div>
</div>
@@ -37,8 +22,12 @@
<script>
import ListTools from '../Widgets/ListTools'
+ import ListWidget from './ListWidget'
export default {
+ components: {
+ ListWidget
+ },
mixins: [ ListTools ],
data() {
return {
diff --git a/src/resources/vue/User/ListWidget.vue b/src/resources/vue/User/ListWidget.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/User/ListWidget.vue
@@ -0,0 +1,32 @@
+<template>
+ <list-table :list="list" :current="current" :setup="setup"></list-table>
+</template>
+
+<script>
+ import { ListTable } from '../Widgets/ListTools'
+
+ export default {
+ components: {
+ ListTable
+ },
+ props: {
+ list: { type: Array, default: () => [] },
+ current: { type: Object, default: () => null }
+ },
+ data() {
+ return {
+ setup: {
+ model: 'user',
+ columns: [
+ {
+ prop: 'email',
+ icon: 'user',
+ label: 'form.primary-email',
+ link: true
+ }
+ ]
+ }
+ }
+ }
+ }
+</script>
diff --git a/src/resources/vue/Widgets/CompanionappList.vue b/src/resources/vue/Widgets/CompanionappList.vue
--- a/src/resources/vue/Widgets/CompanionappList.vue
+++ b/src/resources/vue/Widgets/CompanionappList.vue
@@ -3,21 +3,7 @@
<btn icon="trash-can" class="btn-outline-danger button-delete float-end" @click="showDeleteConfirmation()">
{{ $t('companion.delete') }}
</btn>
- <table class="table table-sm m-0 entries">
- <thead>
- <tr>
- <th scope="col">{{ $t('companion.name') }}</th>
- <th scope="col">{{ $t('companion.deviceid') }}</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="entry in entries" :id="'entry' + entry.id" :key="entry.id">
- <td class="description">{{ entry.name }}</td>
- <td class="description">{{ entry.device_id }}</td>
- </tr>
- </tbody>
- <list-foot :text="$t('companion.nodevices')" :colspan="2"></list-foot>
- </table>
+ <list-table class="m-0" :list="entries" :setup="setup"></list-table>
<list-more v-if="hasMore" :on-click="loadMore"></list-more>
<div id="delete-warning" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
@@ -45,11 +31,22 @@
export default {
mixins: [ ListTools ],
- props: {
- },
data() {
return {
- entries: []
+ entries: [],
+ setup: {
+ model: 'companion',
+ columns: [
+ {
+ prop: 'name'
+ },
+ {
+ prop: 'device_id',
+ label: 'companion.deviceid'
+ }
+ ]
+ }
+
}
},
mounted() {
diff --git a/src/resources/vue/Widgets/ListTools.vue b/src/resources/vue/Widgets/ListTools.vue
--- a/src/resources/vue/Widgets/ListTools.vue
+++ b/src/resources/vue/Widgets/ListTools.vue
@@ -4,7 +4,7 @@
<script>
- const ListSearch = {
+ export const ListSearch = {
props: {
onSearch: { type: Function, default: () => {} },
placeholder: { type: String, default: '' }
@@ -20,7 +20,7 @@
</form>`
}
- const ListFoot = {
+ export const ListFoot = {
props: {
colspan: { type: Number, default: 1 },
text: { type: String, default: '' }
@@ -28,7 +28,7 @@
template: `<tfoot class="table-fake-body"><tr><td :colspan="colspan">{{ text }}</td></tr></tfoot>`
}
- const ListMore = {
+ export const ListMore = {
props: {
onClick: { type: Function, default: () => {} }
},
@@ -37,11 +37,64 @@
</div>`
}
+ export const ListTable = {
+ components: {
+ ListFoot
+ },
+ props: {
+ current: { type: Object, default: () => null },
+ list: { type: Array, default: () => [] },
+ setup: { type: Object, default: () => {} },
+ },
+ methods: {
+ content(column, item) {
+ if (column.contentLabel) {
+ return this.$t(column.contentLabel(item))
+ }
+ if (column.content) {
+ return column.content(item)
+ }
+ return item[column.prop]
+ },
+ label(label) {
+ let l = `${this.setup.prefix || this.setup.model}${label}`
+ return this.$te(l) ? l : `form${label}`
+ },
+ url(item) {
+ return `/${this.setup.model}/${item.id}`
+ }
+ },
+ template:
+ `<table class="table table-sm table-hover">
+ <thead>
+ <tr>
+ <th v-for="column in setup.columns" scope="col">{{ $t(column.label || label('.' + column.prop)) }}</th>
+ <th v-if="setup.buttons" scope="col"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="(item, index) in list" :key="item.id || index" :id="setup.model ? (setup.model + (item.id || index)) : null" @click="$root.clickRecord">
+ <td v-for="column in setup.columns" :key="column.prop + (item.id || index)" :class="column.className">
+ <svg-icon v-if="column.icon" :icon="column.icon" :class="$root.statusClass(item)" :title="$root.statusText(item)"></svg-icon>
+ <router-link v-if="column.link && (!current || current.id != item.id)" :to="url(item)">{{ content(column, item) }}</router-link>
+ <slot v-else-if="column.contentSlot" :name="column.contentSlot" v-bind:item="item"></slot>
+ <span v-else>{{ content(column, item) }}</span>
+ </td>
+ <td v-if="setup.buttons" class="buttons">
+ <slot name="buttons" v-bind:item="item"></slot>
+ </td>
+ </tr>
+ </tbody>
+ <list-foot :text="$t(setup.footLabel || label('.list-empty'))" :colspan="setup.columns.length + (setup.buttons ? 1 : 0)"></list-foot>
+ </table>`
+ }
+
export default {
components: {
ListFoot,
ListMore,
- ListSearch
+ ListSearch,
+ ListTable
},
data() {
return {

File Metadata

Mime Type
text/plain
Expires
Mon, Apr 6, 6:31 PM (1 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18820164
Default Alt Text
D3544.1775500262.diff (47 KB)

Event Timeline