PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,184 @@
/**
* Model for Multisites Dashboard aka All Websites Dashboard.
*/
(function () {
angular.module('piwikApp').factory('multisitesDashboardModel', multisitesDashboardModel);
multisitesDashboardModel.$inject = ['piwikApi', '$filter', '$timeout'];
function multisitesDashboardModel(piwikApi, $filter, $timeout) {
var refreshPromise = null;
// those sites are going to be displayed
var model = {
sites : [],
isLoading : false,
pageSize : 25,
currentPage : 0,
totalVisits : '?',
totalPageviews : '?',
totalActions : '?',
totalRevenue : '?',
searchTerm : '',
lastVisits : '?',
lastVisitsDate : '?',
numberOfSites : 0,
loadingMessage: _pk_translate('MultiSites_LoadingWebsites'),
updateWebsitesList: updateWebsitesList,
getNumberOfFilteredSites: getNumberOfFilteredSites,
getNumberOfPages: getNumberOfPages,
getPaginationLowerBound: getPaginationLowerBound,
getPaginationUpperBound: getPaginationUpperBound,
previousPage: previousPage,
nextPage: nextPage,
searchSite: searchSite,
sortBy: sortBy,
reverse: true,
sortColumn: 'nb_visits',
fetchAllSites: fetchAllSites,
refreshInterval: 0
};
return model;
function cancelRefereshInterval()
{
if (refreshPromise) {
$timeout.cancel(refreshPromise);
refreshPromise = null;
};
}
function onError () {
model.errorLoadingSites = true;
model.sites = [];
}
function updateWebsitesList(report) {
if (!report) {
onError();
return;
}
var allSites = report.sites;
angular.forEach(allSites, function (site, index) {
site.visits_evolution = parseInt(site.visits_evolution, 10);
site.pageviews_evolution = parseInt(site.pageviews_evolution, 10);
site.revenue_evolution = parseInt(site.revenue_evolution, 10);
});
model.totalVisits = report.totals.nb_visits;
model.totalPageviews = report.totals.nb_pageviews;
model.totalActions = report.totals.nb_actions;
model.totalRevenue = report.totals.revenue;
model.lastVisits = report.totals.nb_visits_lastdate;
model.sites = allSites;
model.numberOfSites = report.numSites;
model.lastVisitsDate = report.lastDate;
}
function getNumberOfFilteredSites () {
return model.numberOfSites;
}
function getNumberOfPages() {
return Math.ceil(getNumberOfFilteredSites() / model.pageSize - 1);
}
function getCurrentPagingOffset() {
return Math.ceil(model.currentPage * model.pageSize);
}
function getPaginationLowerBound() {
return getCurrentPagingOffset() + 1;
}
function getPaginationUpperBound() {
var end = getCurrentPagingOffset() + parseInt(model.pageSize, 10);
var max = getNumberOfFilteredSites();
if (end > max) {
end = max;
}
return parseInt(end, 10);
}
function previousPage() {
model.currentPage = model.currentPage - 1;
fetchAllSites();
}
function sortBy(metric) {
if (model.sortColumn == metric) {
model.reverse = !model.reverse;
}
model.sortColumn = metric;
fetchAllSites();
};
function previousPage() {
model.currentPage = model.currentPage - 1;
fetchAllSites();
}
function nextPage() {
model.currentPage = model.currentPage + 1;
fetchAllSites();
}
function searchSite (term) {
model.searchTerm = term;
model.currentPage = 0;
fetchAllSites();
}
function fetchAllSites() {
if (model.isLoading) {
piwikApi.abort();
cancelRefereshInterval();
}
model.isLoading = true;
model.errorLoadingSites = false;
var params = {
module: 'MultiSites',
action: 'getAllWithGroups',
hideMetricsDoc: '1',
filter_sort_order: 'asc',
filter_limit: model.pageSize,
filter_offset: getCurrentPagingOffset(),
showColumns: 'label,nb_visits,nb_pageviews,visits_evolution,pageviews_evolution,revenue_evolution,nb_actions,revenue'
};
if (model.searchTerm) {
params.pattern = model.searchTerm;
}
if (model.sortColumn) {
params.filter_sort_column = model.sortColumn;
}
if (model.reverse) {
params.filter_sort_order = 'desc';
}
return piwikApi.fetch(params).then(function (response) {
updateWebsitesList(response);
}, onError).finally(function () {
model.isLoading = false;
if (model.refreshInterval && model.refreshInterval > 0) {
cancelRefereshInterval();
refreshPromise = $timeout(function () {
refreshPromise = null;
fetchAllSites(model.refreshInterval);
}, model.refreshInterval * 1000);
}
});
}
}
})();

View File

@ -0,0 +1,29 @@
/*!
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
(function () {
angular.module('piwikApp').controller('MultiSitesDashboardController', MultiSitesDashboardController);
MultiSitesDashboardController.$inject = ['$scope', 'piwik', 'multisitesDashboardModel'];
function MultiSitesDashboardController($scope, piwik, multisitesDashboardModel){
$scope.model = multisitesDashboardModel;
$scope.evolutionSelector = 'visits_evolution';
$scope.hasSuperUserAccess = piwik.hasSuperUserAccess;
$scope.date = piwik.broadcast.getValueFromUrl('date');
$scope.idSite = piwik.broadcast.getValueFromUrl('idSite');
$scope.url = piwik.piwik_url;
$scope.period = piwik.period;
$scope.areAdsForProfessionalServicesEnabled = piwik.config && piwik.config.are_ads_enabled;
this.refresh = function (interval) {
multisitesDashboardModel.refreshInterval = interval;
multisitesDashboardModel.fetchAllSites();
};
}
})();

View File

@ -0,0 +1,129 @@
<div>
<h2 piwik-enriched-headline
class="card-title"
help-url="https://matomo.org/docs/manage-websites/#all-websites-dashboard"
feature-name="{{ 'General_AllWebsitesDashboard'|translate }}">
{{ 'General_AllWebsitesDashboard'|translate }}
<span class='smallTitle'
title="{{ 'General_EvolutionSummaryGeneric'|translate:('General_NVisits'|translate:model.totalVisits):date:model.lastVisits:model.lastVisitsDate:(model.totalVisits|evolution:model.lastVisits)}}"
ng-bind-html="'General_TotalVisitsPageviewsActionsRevenue' | translate:('<strong>'+model.totalVisits+'</strong>'):('<strong>'+model.totalPageviews+'</strong>'):('<strong>'+model.totalActions+'</strong>'):('<strong>' + model.totalRevenue + '</strong>')">
</span>
</h2>
<table id="mt" class="dataTable card-table" cellspacing="0">
<thead>
<tr>
<th id="names" class="label" ng-click="model.sortBy('label')" ng-class="{columnSorted: 'label' == model.sortColumn}">
<span class="heading">{{ 'General_Website'|translate }}</span>
<span ng-class="{multisites_asc: !model.reverse && 'label' == model.sortColumn, multisites_desc: model.reverse && 'label' == model.sortColumn}" class="arrow"></span>
</th>
<th id="visits" class="multisites-column" ng-click="model.sortBy('nb_visits')" ng-class="{columnSorted: 'nb_visits' == model.sortColumn}">
<span ng-class="{multisites_asc: !model.reverse && 'nb_visits' == model.sortColumn, multisites_desc: model.reverse && 'nb_visits' == model.sortColumn}" class="arrow"></span>
<span class="heading">{{ 'General_ColumnNbVisits'|translate }}</span>
</th>
<th id="pageviews" class="multisites-column" ng-click="model.sortBy('nb_pageviews')" ng-class="{columnSorted: 'nb_pageviews' == model.sortColumn}">
<span ng-class="{multisites_asc: !model.reverse && 'nb_pageviews' == model.sortColumn, multisites_desc: model.reverse && 'nb_pageviews' == model.sortColumn}" class="arrow"></span>
<span class="heading">{{ 'General_ColumnPageviews'|translate }}</span>
</th>
<th ng-if="displayRevenueColumn" id="revenue" class="multisites-column" ng-click="model.sortBy('revenue')" ng-class="{columnSorted: 'revenue' == model.sortColumn}">
<span ng-class="{multisites_asc: !model.reverse && 'revenue' == model.sortColumn, multisites_desc: model.reverse && 'revenue' == model.sortColumn}" class="arrow"></span>
<span class="heading">{{ 'General_ColumnRevenue'|translate }}</span>
</th>
<th id="evolution" colspan="{{ showSparklines ? 2 : 1 }}" ng-class="{columnSorted: evolutionSelector == model.sortColumn}">
<span class="arrow" ng-class="{multisites_asc: !model.reverse && evolutionSelector == model.sortColumn, multisites_desc: model.reverse && evolutionSelector == model.sortColumn}"></span>
<span class="evolution"
ng-click="model.sortBy(evolutionSelector)"> {{ 'MultiSites_Evolution'|translate }}</span>
<select class="selector browser-default" id="evolution_selector" ng-model="evolutionSelector"
ng-change="model.sortBy(evolutionSelector)">
<option value="visits_evolution">{{ 'General_ColumnNbVisits'|translate }}</option>
<option value="pageviews_evolution">{{ 'General_ColumnPageviews'|translate }}</option>
<option ng-if="displayRevenueColumn" value="revenue_evolution">{{ 'General_ColumnRevenue'|translate }}</option>
</select>
</th>
</tr>
</thead>
<tbody id="tb" ng-if="model.isLoading">
<tr>
<td colspan="7" class="allWebsitesLoading">
<div piwik-activity-indicator loading-message="model.loadingMessage" loading="model.isLoading"></div>
</td>
</tr>
</tbody>
<tbody id="tb" ng-if="!model.isLoading">
<tr ng-if="model.errorLoadingSites">
<td colspan="7">
<div class="notification system notification-error">
{{ 'General_ErrorRequest'|translate:(''):('') }}
<br /><br />
{{ 'General_NeedMoreHelp'|translate }}
<a rel="noreferrer noopener" target="_blank" href="https://matomo.org/faq/troubleshooting/faq_19489/">{{ 'General_Faq'|translate }}</a>
<a rel="noreferrer noopener" target="_blank" href="https://forum.matomo.org/">{{ 'Feedback_CommunityHelp'|translate }}</a>
<span ng-show="areAdsForProfessionalServicesEnabled"> </span>
<a ng-show="areAdsForProfessionalServicesEnabled" rel="noreferrer noopener" target="_blank" href="https://matomo.org/support/?pk_campaign=Help&pk_medium=AjaxError&pk_content=MultiSites&pk_source=Piwik_App">{{ 'Feedback_ProfessionalHelp'|translate }}</a>.
</div>
</td>
</tr>
<tr website="website"
evolution-metric="evolutionSelector"
piwik-multisites-site
date-sparkline="dateSparkline"
show-sparklines="showSparklines"
metric="model.sortColumn"
display-revenue-column="displayRevenueColumn"
ng-repeat="website in model.sites">
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="8" class="paging" ng-hide="model.numberOfPages() <= 1">
<div class="row">
<div class="col s3 add_new_site">
<a ng-if="hasSuperUserAccess" href="{{ url }}?module=SitesManager&action=index&showaddsite=1&period={{ period }}&date={{ date }}&idSite={{ idSite }}">
<span class="icon-add"></span> {{ 'SitesManager_AddSite'|translate }}
</a>
</div>
<div class="col s6">
<span id="prev" class="previous dataTablePrevious" ng-hide="model.currentPage == 0" ng-click="model.previousPage()">
<span style="cursor:pointer;">&#171; {{ 'General_Previous'|translate }}</span>
</span>
<span class="dataTablePages">
<span id="counter">
{{ 'General_Pagination'|translate:model.getPaginationLowerBound():model.getPaginationUpperBound():model.getNumberOfFilteredSites() }}
</span>
</span>
<span id="next" class="next dataTableNext" ng-hide="model.currentPage >= model.getNumberOfPages()" ng-click="model.nextPage()">
<span style="cursor:pointer;" class="pointer">{{ 'General_Next'|translate }} &#187;</span>
</span>
</div>
<div class="col s3">&nbsp;</div>
</div>
</td>
</tr>
<tr row_id="last">
<td colspan="8" class="input-field site_search">
<input type="text"
ng-model="searchTerm"
class="browser-default"
piwik-onenter="model.searchSite(searchTerm)"
placeholder="{{ 'Actions_SubmenuSitesearch' | translate }}">
<span title="{{ 'General_ClickToSearch' | translate }}"
ng-click="model.searchSite(searchTerm)"
class="icon-search search_ico"></span>
</td>
</tr>
</tfoot>
</table>
</div>

View File

@ -0,0 +1,46 @@
/*!
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
/**
* Renders the multisites dashboard
* Example usage:
*
* <div piwik-multisites-dashboard
* display-revenue-column="true"
* show-sparklines="true"
* date-sparkline="true"
* page-size="50"
* auto-refresh-today-report="500" // or 0 to disable
* ></div>
*/
(function () {
angular.module('piwikApp').directive('piwikMultisitesDashboard', piwikMultisitesDashboard);
piwikMultisitesDashboard.$inject = ['piwik'];
function piwikMultisitesDashboard(piwik){
return {
restrict: 'A',
scope: {
displayRevenueColumn: '@',
showSparklines: '@',
dateSparkline: '@'
},
templateUrl: 'plugins/MultiSites/angularjs/dashboard/dashboard.directive.html?cb=' + piwik.cacheBuster,
controller: 'MultiSitesDashboardController',
link: function (scope, element, attrs, controller) {
if (attrs.pageSize) {
scope.model.pageSize = attrs.pageSize;
}
controller.refresh(attrs.autoRefreshTodayReport);
}
};
}
})();

View File

@ -0,0 +1,275 @@
.smallTitle {
font-size: 15px;
}
.widget {
#multisites {
padding: 15px;
}
}
#mt {
table.dataTable td.label img {
margin-top: -8px;
}
}
#multisites {
> .col {
padding-left: 0;
padding-right: 0;
}
.notification-error {
margin-top: 15px;
a {
text-decoration: underline !important;
}
}
.add_new_site {
border: 0 !important;
font-size: 13px;
text-align: left;
padding-left: 27px;
a {
color: @theme-color-text;
&:hover {
text-decoration: underline !important;
}
}
}
.clean {
border: 0 !important;
text-align: right;
padding-right:10px;
padding-top: 19px;
padding-bottom: 5px;
}
@media print{
.add_new_site{
display: none;
}
.row .col.s6{
width: 100%;
}
.row .col.s3{
display: none;
}
}
.site_search {
padding: 0;
text-align: center;
border: 0 !important;
@media print{
display: none;
}
}
.multisites-evolution,
.multisites-column {
text-align: right;
}
.multisites-evolution {
width:170px;
}
td, tr, .sparkline {
text-align: center;
vertical-align: middle;
}
td.empty-row {
border-bottom: none !important;
}
.paging {
padding: 5px;
border-bottom: 0 !important;
.row {
margin-top: 16px;
}
.previous {
visibility: visible;
}
.next {
visibility: visible;
}
}
th:first-child {
text-align:left;
padding-left: 32px;
}
th {
cursor: pointer;
text-align: right;
padding-right: 0 !important;
&#evolution {
text-align: center;
}
&.columnSorted {
font-weight: normal !important;
}
}
.site_search input {
margin-right: 0;
margin-left: 25px;
padding-right: 25px;
width: 250px;
height: 3rem;
}
.search_ico {
position: relative;
left: -20px;
top: 1px;
cursor: pointer;
font-size: 16px;
}
.reset {
position: relative;
left: -25px;
cursor: pointer;
margin-right: 0;
}
tr.group {
font-weight: bold;
height: 30px;
}
tr.groupedWebsite .label {
padding-left: 50px;
}
td.multisites-label {
text-align: left;
width: 250px;
max-width: 250px;
padding-left: 32px;
a {
width: auto;
}
}
td.multisites-label a:hover {
text-decoration: underline;
}
td.multisites-column,
th.multisites-column {
width: 70px;
white-space: nowrap;
}
td.multisites-column-evolution,
th.multisites-column-evolution {
width: 70px;
}
th#evolution {
width:350px;
}
th#visits {
width: 100px;
}
th#pageviews {
width: 110px;
}
th#revenue {
width: 110px;
}
.evolution {
cursor:pointer;
}
.allWebsitesLoading {
padding:20px
}
.heading {
display: inline;
margin-top: 4px;
}
#evolution_selector {
height: 28px;
margin: -9px 0 0 5px;
width: 80px;
display: inline-block;
}
.label .arrow {
margin-left: 2px;
}
.multisites_asc,
.multisites_desc {
float: none;
display: inline-block;
vertical-align: top;
margin: 0;
margin-left: 6px;
margin-top: -1px;
}
#evolution {
.multisites_asc,
.multisites_desc {
margin-right: 6px;
margin-left: 0;
}
.evolution {
vertical-align: top;
}
}
.multisites_asc {
margin-top: -7px;
vertical-align: top;
}
.multisites_desc:after {
content: " \25BC";
font-size: 1px;
color: @theme-color-brand;
border-left: 4px solid rgba(0, 0, 0, 0);
border-right: 4px solid rgba(0, 0, 0, 0);
border-top: 5px solid @theme-color-brand;
}
.multisites_asc:after {
content: " \25BC";
font-size: 1px;
color: @theme-color-brand;
border-left: 4px solid rgba(0, 0, 0, 0);
border-right: 4px solid rgba(0, 0, 0, 0);
border-bottom: 5px solid @theme-color-brand;
}
div.sparkline {
float:none;
}
tfoot td {
border-bottom: 0;
}
}