diff --git a/assets/admin/app.js b/assets/admin/app.js
index f8c3475f..852c3427 100644
--- a/assets/admin/app.js
+++ b/assets/admin/app.js
@@ -1 +1,5 @@
// Add project specific javascript code and import of additional bundles here:
+import {viewRegistry} from 'sulu-admin-bundle/containers';
+import ContactStatistics from "./views/ContactStatistics";
+
+viewRegistry.add('app.contact_statistics', ContactStatistics);
diff --git a/assets/admin/views/ContactStatistics.js b/assets/admin/views/ContactStatistics.js
new file mode 100644
index 00000000..bf8ba4e6
--- /dev/null
+++ b/assets/admin/views/ContactStatistics.js
@@ -0,0 +1,76 @@
+import React from 'react';
+import {observer} from 'mobx-react';
+import {action, observable} from 'mobx';
+import {Loader, Button} from 'sulu-admin-bundle/components';
+import {withToolbar} from 'sulu-admin-bundle/containers';
+import {translate} from 'sulu-admin-bundle/utils';
+import {ResourceRequester} from 'sulu-admin-bundle/services';
+
+@observer
+class ContactStatistics extends React.Component {
+ @observable loading = false;
+ @observable contactCount = undefined;
+
+ componentDidMount() {
+ this.loadData();
+ }
+
+ @action loadData = () => {
+ this.loading = true;
+ this.contactCount = undefined;
+ const contactResourceKey = this.props.router.route.options.contactResourceKey;
+
+ return ResourceRequester.getList(contactResourceKey)
+ .then(action((response) => {
+ this.contactCount = response.total;
+ }))
+ .catch((e) => {
+ console.error('Error while loading contact statistics from server.', e);
+ })
+ .finally(action(() => {
+ this.loading = false;
+ }));
+ }
+
+ navigateToContactList = () => {
+ const contactListView = this.props.router.route.options.contactListView;
+
+ this.props.router.navigate(contactListView);
+ }
+
+ render() {
+ if (this.loading) {
+ return ;
+ }
+
+ return (
+
+
+ {translate('app.contact_statistics_count_text', {contactCount: this.contactCount})}
+
+
+
+ );
+ }
+}
+
+export default withToolbar(ContactStatistics, function () {
+ return {
+ items: [
+ {
+ type: 'button',
+ label: translate('app.refresh_statistics'),
+ icon: 'su-sync',
+ disabled: this.loading,
+ onClick: () => {
+ this.loadData();
+ },
+ }
+ ]
+ };
+});
diff --git a/src/Admin/ContactStatisticsAdmin.php b/src/Admin/ContactStatisticsAdmin.php
new file mode 100644
index 00000000..6daaaf35
--- /dev/null
+++ b/src/Admin/ContactStatisticsAdmin.php
@@ -0,0 +1,62 @@
+viewBuilderFactory = $viewBuilderFactory;
+ $this->securityChecker = $securityChecker;
+ }
+
+ public function configureNavigationItems(NavigationItemCollection $navigationItemCollection): void
+ {
+ if (!$navigationItemCollection->has('sulu_contact.contacts')) {
+ return;
+ }
+
+ if ($this->securityChecker->hasPermission(ContactAdmin::CONTACT_SECURITY_CONTEXT, PermissionTypes::VIEW)) {
+ $contactStatisticsNavigationItem = new NavigationItem('app.contact_statistics');
+ $contactStatisticsNavigationItem->setPosition(30);
+ $contactStatisticsNavigationItem->setView(static::CONTACT_STATISTICS_VIEW);
+
+ $contactsNavigationItem = $navigationItemCollection->get('sulu_contact.contacts');
+ $contactsNavigationItem->addChild($contactStatisticsNavigationItem);
+ }
+ }
+
+ public function configureViews(ViewCollection $viewCollection): void
+ {
+ if ($this->securityChecker->hasPermission(ContactAdmin::CONTACT_SECURITY_CONTEXT, PermissionTypes::VIEW)) {
+ $viewCollection->add(
+ $this->viewBuilderFactory->createViewBuilder(self::CONTACT_STATISTICS_VIEW, '/contact-statistics', 'app.contact_statistics')
+ ->setOption('contactListView', ContactAdmin::CONTACT_LIST_VIEW)
+ ->setOption('contactResourceKey', 'contacts')
+ );
+ }
+ }
+
+ public static function getPriority(): int
+ {
+ return ContactAdmin::getPriority() - 1;
+ }
+}
diff --git a/translations/admin.de.json b/translations/admin.de.json
index 4565f68a..32521278 100644
--- a/translations/admin.de.json
+++ b/translations/admin.de.json
@@ -10,5 +10,9 @@
"app.album_selection_label": "{count} {count, plural, =1 {Album} other {Alben}} ausgewählt",
"app.select_albums": "Alben auswählen",
"app.no_album_selected": "Kein Album ausgewählt",
- "app.select_album": "Album auswählen"
+ "app.select_album": "Album auswählen",
+ "app.contact_statistics": "Statistiken",
+ "app.refresh_statistics": "Stastiken aktualisieren",
+ "app.contact_statistics_count_text": "Die Applikation enthält {contactCount} Kontakte.",
+ "app.contact_statistics_link_text": "Navigiere zur Kontaktliste"
}
diff --git a/translations/admin.en.json b/translations/admin.en.json
index 2160e113..013fc35d 100644
--- a/translations/admin.en.json
+++ b/translations/admin.en.json
@@ -10,5 +10,9 @@
"app.album_selection_label": "{count} {count, plural, =1 {album} other {albums}} selected",
"app.select_albums": "Select albums",
"app.no_album_selected": "No album selected",
- "app.select_album": "Select album"
+ "app.select_album": "Select album",
+ "app.contact_statistics": "Statistics",
+ "app.refresh_statistics": "Refresh Statistics",
+ "app.contact_statistics_count_text": "The application includes {contactCount} contacts at the moment.",
+ "app.contact_statistics_link_text": "Navigate to the contact list"
}