diff --git a/TAKEHOME.md b/TAKEHOME.md new file mode 100644 index 00000000000..a283e150ad9 --- /dev/null +++ b/TAKEHOME.md @@ -0,0 +1,47 @@ +### Quick Stats + +This is a simple feature to show some quick stats about the Visits and Actions in the last 120mins. +This is made of a single Vue component (QuickStats.vue) that displays a button at the foot of each page. +Clicking the button will show a modal with the stats taken from the API endpoint given. +The vue component is then injected into the footer using `Template.pageFooter` hook. +### How this works +This feature uses a Vue component to display the stats. +It fetches the data from the Matomo API using AjaxHelper component to get data from `Live.getCounters` method, +which returns the last visits, their actions and other statistics. + +### Initial Setup + - Create fake visits in the last 120 minutes using + ``` + ddev matomo:console plugin:activate VisitorGenerator + ddev matomo:console visitorgenerator:generate-visits + ``` + - Make sure the `Live.getCounters` API method is enabled in your Matomo instance. + - Make sure to enable the `QuickStats` plugin in your Matomo instance. + - You can enable the plugin using the following command: + ``` + ddev matomo:console plugin:activate QuickStats + ``` + - Alternatively, you can enable it from the Matomo UI by going to the "Plugins" section and activating the "QuickStats" plugin. +### Future Improvements + - The current implementation is a basic one. + - Make the UI look better by styling the footer button more and making the statistics cards more visually appealing. + - The Vue component could be made more reusable by passing in the API `lastMinutes` parameter as a prop. + - Would also be good to pass the `idSite` parameter as a prop especially if there are more than 1 website added in Matomo. + +### Running the Test + - To run the test, you can use the following command: + ``` + ddev matomo:console test:run-ui --plugin=QuickStats + ``` + - There are a few gotchas with running the tests: + - Remember to use `ddev matomo:console test:run-ui --plugin=PluginName` instead of `./console test:run-ui --plugin=QuickStats` + to ensure the correct environment is used. + + +### Other Testing Considerations + - I would probably add a SystemTest to check that the api we use `Live.getCounters` is returning the expected data. + - I will put this under `plugin/QuickStats/tests/System` + - I'll also add in an integreation test to check that the Vue component is rendering correctly and that the data is being displayed as expected. + - This should also test that when the button is clicked the modal opens. + - This could also test that when the modal is opened, the API to fetch counters is called and that the data is displayed correctly. + - This will be under `plugin/QuickStats/tests/Integration` \ No newline at end of file diff --git a/mysqldefaults.conf b/mysqldefaults.conf new file mode 100644 index 00000000000..1d6de86e912 --- /dev/null +++ b/mysqldefaults.conf @@ -0,0 +1,3 @@ +[client] +user=db +password=db diff --git a/plugins/QuickStats/CHANGELOG.md b/plugins/QuickStats/CHANGELOG.md new file mode 100644 index 00000000000..854631896a5 --- /dev/null +++ b/plugins/QuickStats/CHANGELOG.md @@ -0,0 +1,3 @@ +## Changelog + +Here goes the changelog text. diff --git a/plugins/QuickStats/QuickStats.php b/plugins/QuickStats/QuickStats.php new file mode 100644 index 00000000000..3600f9c50b3 --- /dev/null +++ b/plugins/QuickStats/QuickStats.php @@ -0,0 +1,36 @@ + 'getArchivingAPIMethodForPlugin', + 'Template.pageFooter' => 'getPageFooter', + ]; + } + + // support archiving just this plugin via core:archive + public function getArchivingAPIMethodForPlugin(&$method, $plugin) + { + if ($plugin == 'QuickStats') { + $method = 'QuickStats.getExampleArchivedMetric'; + } + } + public function getPageFooter(&$out) + { + $view = new View('@QuickStats/footer.twig'); + $out .= $view->render(); + } +} \ No newline at end of file diff --git a/plugins/QuickStats/README.md b/plugins/QuickStats/README.md new file mode 100644 index 00000000000..2f497cf2672 --- /dev/null +++ b/plugins/QuickStats/README.md @@ -0,0 +1,6 @@ +# Matomo QuickStats Plugin + +## Description + +Add your plugin description here. + diff --git a/plugins/QuickStats/config/config.php b/plugins/QuickStats/config/config.php new file mode 100644 index 00000000000..d5be5de26f9 --- /dev/null +++ b/plugins/QuickStats/config/config.php @@ -0,0 +1,3 @@ +=5.4.0-b4,<6.0.0-b1" + }, + "authors": [ + { + "name": "Matomo", + "email": "", + "homepage": "" + } + ], + "support": { + "email": "", + "issues": "", + "forum": "", + "irc": "", + "wiki": "", + "source": "", + "docs": "", + "rss": "" + }, + "homepage": "", + "license": "GPL v3+", + "keywords": [] +} \ No newline at end of file diff --git a/plugins/QuickStats/screenshots/.gitkeep b/plugins/QuickStats/screenshots/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/QuickStats/stylesheets/footer.less b/plugins/QuickStats/stylesheets/footer.less new file mode 100644 index 00000000000..88748cbc9ef --- /dev/null +++ b/plugins/QuickStats/stylesheets/footer.less @@ -0,0 +1,9 @@ +#footerLinks { + text-align: center; + font-size: .7rem; + color: @color-silver; + + a { + color: @color-silver; + } +} \ No newline at end of file diff --git a/plugins/QuickStats/templates/footer.twig b/plugins/QuickStats/templates/footer.twig new file mode 100644 index 00000000000..76733c01f67 --- /dev/null +++ b/plugins/QuickStats/templates/footer.twig @@ -0,0 +1,3 @@ +
\ No newline at end of file diff --git a/plugins/QuickStats/tests/UI/.gitignore b/plugins/QuickStats/tests/UI/.gitignore new file mode 100644 index 00000000000..f39be478e7a --- /dev/null +++ b/plugins/QuickStats/tests/UI/.gitignore @@ -0,0 +1,2 @@ +/processed-ui-screenshots +/screenshot-diffs \ No newline at end of file diff --git a/plugins/QuickStats/tests/UI/QuickStatsDialog_spec.js b/plugins/QuickStats/tests/UI/QuickStatsDialog_spec.js new file mode 100644 index 00000000000..d022e451672 --- /dev/null +++ b/plugins/QuickStats/tests/UI/QuickStatsDialog_spec.js @@ -0,0 +1,29 @@ +/*! + * Matomo - free/libre analytics platform + * + * Screenshot integration tests. + * + * @link https://matomo.org + * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +describe("QuickStatsDialog", function () { + this.timeout(0); + + it('should show the QuickStats dialog', async function () { + await page.goto("?module=CoreHome&action=index&idSite=1&period=day&date=today"); + await page.waitForNetworkIdle(); + + // Wait for and click the QuickStats button (adjust selector if needed) + await page.waitForSelector('.quick-stat-component .btn-flat'); + await page.click('.quick-stat-component .btn-flat'); + + // Wait for the dialog to appear + await page.waitForSelector('.card-container'); + await page.waitForNetworkIdle(); + + // Take a screenshot of the dialog + const dialog = await page.$('.card-container'); + expect(await dialog.screenshot()).to.matchImage('QuickStatsDialog'); + }); +}); diff --git a/plugins/QuickStats/tests/UI/expected-screenshots/.gitkeep b/plugins/QuickStats/tests/UI/expected-screenshots/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/QuickStats/tests/UI/expected-screenshots/QuickStatsDialog_QuickStatsDialog.png b/plugins/QuickStats/tests/UI/expected-screenshots/QuickStatsDialog_QuickStatsDialog.png new file mode 100644 index 00000000000..f72a5005fad --- /dev/null +++ b/plugins/QuickStats/tests/UI/expected-screenshots/QuickStatsDialog_QuickStatsDialog.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:113adcb292db488617a3ca6f1a7760e974d440c9b6aafe94010ab98b5824335d +size 5077 diff --git a/plugins/QuickStats/vue/dist/QuickStats.css b/plugins/QuickStats/vue/dist/QuickStats.css new file mode 100644 index 00000000000..7f37e981e89 --- /dev/null +++ b/plugins/QuickStats/vue/dist/QuickStats.css @@ -0,0 +1 @@ +.quick-stat-component[data-v-41659524]{display:flex;justify-content:center;align-items:center}.card-container[data-v-41659524]{margin-top:200px} \ No newline at end of file diff --git a/plugins/QuickStats/vue/dist/QuickStats.umd.js b/plugins/QuickStats/vue/dist/QuickStats.umd.js new file mode 100644 index 00000000000..ac56032f75a --- /dev/null +++ b/plugins/QuickStats/vue/dist/QuickStats.umd.js @@ -0,0 +1,320 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("CoreHome"), require("vue")); + else if(typeof define === 'function' && define.amd) + define(["CoreHome", ], factory); + else if(typeof exports === 'object') + exports["QuickStats"] = factory(require("CoreHome"), require("vue")); + else + root["QuickStats"] = factory(root["CoreHome"], root["Vue"]); +})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__19dc__, __WEBPACK_EXTERNAL_MODULE__8bbf__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "plugins/QuickStats/vue/dist/"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "fae3"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "19dc": +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__19dc__; + +/***/ }), + +/***/ "32ce": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony import */ var _node_modules_vue_cli_service_node_modules_mini_css_extract_plugin_dist_loader_js_ref_11_oneOf_1_0_node_modules_vue_cli_service_node_modules_css_loader_dist_cjs_js_ref_11_oneOf_1_1_node_modules_vue_cli_service_node_modules_vue_loader_v16_dist_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_11_oneOf_1_2_node_modules_less_loader_dist_cjs_js_ref_11_oneOf_1_3_node_modules_vue_cli_service_node_modules_cache_loader_dist_cjs_js_ref_1_0_node_modules_vue_cli_service_node_modules_vue_loader_v16_dist_index_js_ref_1_1_QuickStats_vue_vue_type_style_index_0_id_41659524_lang_less_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("b74c"); +/* harmony import */ var _node_modules_vue_cli_service_node_modules_mini_css_extract_plugin_dist_loader_js_ref_11_oneOf_1_0_node_modules_vue_cli_service_node_modules_css_loader_dist_cjs_js_ref_11_oneOf_1_1_node_modules_vue_cli_service_node_modules_vue_loader_v16_dist_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_11_oneOf_1_2_node_modules_less_loader_dist_cjs_js_ref_11_oneOf_1_3_node_modules_vue_cli_service_node_modules_cache_loader_dist_cjs_js_ref_1_0_node_modules_vue_cli_service_node_modules_vue_loader_v16_dist_index_js_ref_1_1_QuickStats_vue_vue_type_style_index_0_id_41659524_lang_less_scoped_true__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_cli_service_node_modules_mini_css_extract_plugin_dist_loader_js_ref_11_oneOf_1_0_node_modules_vue_cli_service_node_modules_css_loader_dist_cjs_js_ref_11_oneOf_1_1_node_modules_vue_cli_service_node_modules_vue_loader_v16_dist_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_11_oneOf_1_2_node_modules_less_loader_dist_cjs_js_ref_11_oneOf_1_3_node_modules_vue_cli_service_node_modules_cache_loader_dist_cjs_js_ref_1_0_node_modules_vue_cli_service_node_modules_vue_loader_v16_dist_index_js_ref_1_1_QuickStats_vue_vue_type_style_index_0_id_41659524_lang_less_scoped_true__WEBPACK_IMPORTED_MODULE_0__); +/* unused harmony reexport * */ + + +/***/ }), + +/***/ "8bbf": +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__8bbf__; + +/***/ }), + +/***/ "b74c": +/***/ (function(module, exports, __webpack_require__) { + +// extracted by mini-css-extract-plugin + +/***/ }), + +/***/ "fae3": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +// ESM COMPAT FLAG +__webpack_require__.r(__webpack_exports__); + +// EXPORTS +__webpack_require__.d(__webpack_exports__, "QuickStats", function() { return /* reexport */ QuickStats; }); + +// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js +// This file is imported into lib/wc client bundles. + +if (typeof window !== 'undefined') { + var currentScript = window.document.currentScript + if (false) { var getCurrentScript; } + + var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/) + if (src) { + __webpack_require__.p = src[1] // eslint-disable-line + } +} + +// Indicate to webpack that this file can be concatenated +/* harmony default export */ var setPublicPath = (null); + +// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"} +var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__("8bbf"); + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--13-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/QuickStats/vue/src/QuickStats/QuickStats.vue?vue&type=template&id=41659524&scoped=true + +const _withScopeId = n => (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["pushScopeId"])("data-v-41659524"), n = n(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["popScopeId"])(), n); +const _hoisted_1 = { + class: "quick-stat-component" +}; +const _hoisted_2 = /*#__PURE__*/_withScopeId(() => /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", { + class: "icon-info" +}, null, -1)); +const _hoisted_3 = { + class: "ui-confirm quick-stat-dialog-content" +}; +const _hoisted_4 = /*#__PURE__*/_withScopeId(() => /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h2", null, "Visitor Stats", -1)); +const _hoisted_5 = { + class: "card-container", + style: { + "margin-top": "20px" + } +}; +const _hoisted_6 = { + class: "row" +}; +const _hoisted_7 = { + class: "col s12 m6" +}; +const _hoisted_8 = { + class: "card" +}; +const _hoisted_9 = { + class: "card-content center-align" +}; +const _hoisted_10 = { + class: "col s12 m6" +}; +const _hoisted_11 = { + class: "card" +}; +const _hoisted_12 = { + class: "card-content center-align" +}; +const _hoisted_13 = { + class: "row" +}; +const _hoisted_14 = { + class: "col s12 m6" +}; +const _hoisted_15 = { + class: "card" +}; +const _hoisted_16 = { + class: "card-content center-align" +}; +const _hoisted_17 = { + class: "col s12 m6" +}; +const _hoisted_18 = { + class: "card" +}; +const _hoisted_19 = { + class: "card-content center-align" +}; +const _hoisted_20 = /*#__PURE__*/_withScopeId(() => /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", { + type: "button", + value: "OK", + role: "yes" +}, null, -1)); +function render(_ctx, _cache, $props, $setup, $data, $options) { + const _component_ActivityIndicator = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("ActivityIndicator"); + const _component_MatomoDialog = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("MatomoDialog"); + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", { + class: "btn-flat", + target: "_blank", + onClick: _cache[0] || (_cache[0] = (...args) => _ctx.showQuickStatsDialog && _ctx.showQuickStatsDialog(...args)) + }, [_hoisted_2, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" Quick Stats ")]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_MatomoDialog, { + modelValue: _ctx.showDialog, + "onUpdate:modelValue": _cache[1] || (_cache[1] = $event => _ctx.showDialog = $event) + }, { + default: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(() => [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_3, [_hoisted_4, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_ActivityIndicator, { + loading: _ctx.loading + }, null, 8, ["loading"]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_5, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_6, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_7, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_8, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_9, " Visits: " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.visits), 1)])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_10, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_11, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_12, " Visitors: " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.visitors), 1)])])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_13, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_14, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_15, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_16, " Actions: " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.actions), 1)])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_17, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_18, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_19, " Visits Converted: " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.visitsConverted), 1)])])])], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], !_ctx.loading]]), _hoisted_20])]), + _: 1 + }, 8, ["modelValue"])]); +} +// CONCATENATED MODULE: ./plugins/QuickStats/vue/src/QuickStats/QuickStats.vue?vue&type=template&id=41659524&scoped=true + +// EXTERNAL MODULE: external "CoreHome" +var external_CoreHome_ = __webpack_require__("19dc"); + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--15-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--15-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--1-1!./plugins/QuickStats/vue/src/QuickStats/QuickStats.vue?vue&type=script&lang=ts + + +/* harmony default export */ var QuickStatsvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({ + components: { + MatomoDialog: external_CoreHome_["MatomoDialog"], + ActivityIndicator: external_CoreHome_["ActivityIndicator"] + }, + data() { + return { + showDialog: false, + loading: true, + visits: '0', + actions: '0', + visitors: '0', + visitsConverted: '0' + }; + }, + watch: { + showDialog(val) { + if (val) { + this.getQuickStats(); + } + } + }, + methods: { + showQuickStatsDialog() { + this.showDialog = true; + }, + getQuickStats() { + external_CoreHome_["AjaxHelper"].fetch({ + method: 'Live.getCounters', + idSite: 1, + lastMinutes: 120, + format: 'json' + }).then(response => { + const resp = response[0]; + this.visits = resp.visits; + this.actions = resp.actions; + this.visitors = resp.visitors; + this.visitsConverted = resp.visitsConverted; + this.loading = false; + }); + } + } +})); +// CONCATENATED MODULE: ./plugins/QuickStats/vue/src/QuickStats/QuickStats.vue?vue&type=script&lang=ts + +// EXTERNAL MODULE: ./plugins/QuickStats/vue/src/QuickStats/QuickStats.vue?vue&type=style&index=0&id=41659524&lang=less&scoped=true +var QuickStatsvue_type_style_index_0_id_41659524_lang_less_scoped_true = __webpack_require__("32ce"); + +// CONCATENATED MODULE: ./plugins/QuickStats/vue/src/QuickStats/QuickStats.vue + + + + + +QuickStatsvue_type_script_lang_ts.render = render +QuickStatsvue_type_script_lang_ts.__scopeId = "data-v-41659524" + +/* harmony default export */ var QuickStats = (QuickStatsvue_type_script_lang_ts); +// CONCATENATED MODULE: ./plugins/QuickStats/vue/src/index.ts + +// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib-no-default.js + + + + +/***/ }) + +/******/ }); +}); +//# sourceMappingURL=QuickStats.umd.js.map \ No newline at end of file diff --git a/plugins/QuickStats/vue/dist/QuickStats.umd.min.js b/plugins/QuickStats/vue/dist/QuickStats.umd.min.js new file mode 100644 index 00000000000..3ebb0d47a69 --- /dev/null +++ b/plugins/QuickStats/vue/dist/QuickStats.umd.min.js @@ -0,0 +1,2 @@ +(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("CoreHome"),require("vue")):"function"===typeof define&&define.amd?define(["CoreHome"],t):"object"===typeof exports?exports["QuickStats"]=t(require("CoreHome"),require("vue")):e["QuickStats"]=t(e["CoreHome"],e["Vue"])})("undefined"!==typeof self?self:this,(function(e,t){return function(e){var t={};function o(c){if(t[c])return t[c].exports;var n=t[c]={i:c,l:!1,exports:{}};return e[c].call(n.exports,n,n.exports,o),n.l=!0,n.exports}return o.m=e,o.c=t,o.d=function(e,t,c){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:c})},o.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var c=Object.create(null);if(o.r(c),Object.defineProperty(c,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)o.d(c,n,function(t){return e[t]}.bind(null,n));return c},o.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="plugins/QuickStats/vue/dist/",o(o.s="fae3")}({"19dc":function(t,o){t.exports=e},"32ce":function(e,t,o){"use strict";o("b74c")},"8bbf":function(e,o){e.exports=t},b74c:function(e,t,o){},fae3:function(e,t,o){"use strict";if(o.r(t),o.d(t,"QuickStats",(function(){return C})),"undefined"!==typeof window){var c=window.document.currentScript,n=c&&c.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);n&&(o.p=n[1])}var i=o("8bbf");const r=e=>(Object(i["pushScopeId"])("data-v-41659524"),e=e(),Object(i["popScopeId"])(),e),s={class:"quick-stat-component"},a=r(()=>Object(i["createElementVNode"])("span",{class:"icon-info"},null,-1)),l={class:"ui-confirm quick-stat-dialog-content"},d=r(()=>Object(i["createElementVNode"])("h2",null,"Visitor Stats",-1)),u={class:"card-container",style:{"margin-top":"20px"}},b={class:"row"},f={class:"col s12 m6"},v={class:"card"},m={class:"card-content center-align"},p={class:"col s12 m6"},j={class:"card"},O={class:"card-content center-align"},g={class:"row"},V={class:"col s12 m6"},h={class:"card"},y={class:"card-content center-align"},S={class:"col s12 m6"},N={class:"card"},E={class:"card-content center-align"},w=r(()=>Object(i["createElementVNode"])("input",{type:"button",value:"OK",role:"yes"},null,-1));function k(e,t,o,c,n,r){const k=Object(i["resolveComponent"])("ActivityIndicator"),D=Object(i["resolveComponent"])("MatomoDialog");return Object(i["openBlock"])(),Object(i["createElementBlock"])("div",s,[Object(i["createElementVNode"])("a",{class:"btn-flat",target:"_blank",onClick:t[0]||(t[0]=(...t)=>e.showQuickStatsDialog&&e.showQuickStatsDialog(...t))},[a,Object(i["createTextVNode"])(" Quick Stats ")]),Object(i["createVNode"])(D,{modelValue:e.showDialog,"onUpdate:modelValue":t[1]||(t[1]=t=>e.showDialog=t)},{default:Object(i["withCtx"])(()=>[Object(i["createElementVNode"])("div",l,[d,Object(i["createVNode"])(k,{loading:e.loading},null,8,["loading"]),Object(i["withDirectives"])(Object(i["createElementVNode"])("div",u,[Object(i["createElementVNode"])("div",b,[Object(i["createElementVNode"])("div",f,[Object(i["createElementVNode"])("div",v,[Object(i["createElementVNode"])("div",m," Visits: "+Object(i["toDisplayString"])(e.visits),1)])]),Object(i["createElementVNode"])("div",p,[Object(i["createElementVNode"])("div",j,[Object(i["createElementVNode"])("div",O," Visitors: "+Object(i["toDisplayString"])(e.visitors),1)])])]),Object(i["createElementVNode"])("div",g,[Object(i["createElementVNode"])("div",V,[Object(i["createElementVNode"])("div",h,[Object(i["createElementVNode"])("div",y," Actions: "+Object(i["toDisplayString"])(e.actions),1)])]),Object(i["createElementVNode"])("div",S,[Object(i["createElementVNode"])("div",N,[Object(i["createElementVNode"])("div",E," Visits Converted: "+Object(i["toDisplayString"])(e.visitsConverted),1)])])])],512),[[i["vShow"],!e.loading]]),w])]),_:1},8,["modelValue"])])}var D=o("19dc"),x=Object(i["defineComponent"])({components:{MatomoDialog:D["MatomoDialog"],ActivityIndicator:D["ActivityIndicator"]},data(){return{showDialog:!1,loading:!0,visits:"0",actions:"0",visitors:"0",visitsConverted:"0"}},watch:{showDialog(e){e&&this.getQuickStats()}},methods:{showQuickStatsDialog(){this.showDialog=!0},getQuickStats(){D["AjaxHelper"].fetch({method:"Live.getCounters",idSite:1,lastMinutes:120,format:"json"}).then(e=>{const t=e[0];this.visits=t.visits,this.actions=t.actions,this.visitors=t.visitors,this.visitsConverted=t.visitsConverted,this.loading=!1})}}});o("32ce");x.render=k,x.__scopeId="data-v-41659524";var C=x}})})); +//# sourceMappingURL=QuickStats.umd.min.js.map \ No newline at end of file diff --git a/plugins/QuickStats/vue/dist/umd.metadata.json b/plugins/QuickStats/vue/dist/umd.metadata.json new file mode 100644 index 00000000000..9ecfcc04562 --- /dev/null +++ b/plugins/QuickStats/vue/dist/umd.metadata.json @@ -0,0 +1,5 @@ +{ + "dependsOn": [ + "CoreHome" + ] +} \ No newline at end of file diff --git a/plugins/QuickStats/vue/src/QuickStats/QuickStats.vue b/plugins/QuickStats/vue/src/QuickStats/QuickStats.vue new file mode 100644 index 00000000000..fe5ec0ac41f --- /dev/null +++ b/plugins/QuickStats/vue/src/QuickStats/QuickStats.vue @@ -0,0 +1,124 @@ + + + +