diff options
author | dizzy <diosmosis@users.noreply.github.com> | 2022-03-03 19:20:02 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-03 19:20:02 +0300 |
commit | 56efd4c7d06aef3435cf531ab6264529eb7fc9b3 (patch) | |
tree | 40db2c1fd1439ac8b619bfde2c381899e83f678e /plugins | |
parent | 80fbf58d7085396d10fd7f596f2bbaeeae36d931 (diff) |
[Vue] migrate single-metric-view component to vue (#18807)
* migrate archiving controller
* do not do a passthrough transpile of vue typescript, and fix many typescript errors in existing code
* more typescript fixes
* even more fixes
* workarounds to fix recursive typing issues
* get corehome to build w/ full typescript build and output type definitions to local dir
* get outputted typings to be used when compiling other plugins and fix typescript issues in CorePluginsAdmin
* readd corehome umd
* fix typescript errors in ExampleVue plugin
* fix feedback typescript errors
* rebuild
* migrate branding controller and get to build
* fix issues and get to work
* rebuild
* fix notification scroll
* migrate smtp settings controller in coreadminhome
* get to work
* migrate js tracking code generator and get to build
* migrate image tracking code generator and get to build
* get to work in UI
* get UI tests to pass locally
* forgot to add files + rebuild vue
* update screenshots
* Show a summary of new features (#18065)
* Added "What is new" notification display, populated by a new event
* Removed test example event hook
* Added support for applying a link attribute to menu items, fixes layout issue for mobile with html menu items
* Updated UI test screenshots
* Revert accidental edit
* Hide the "What's new" icon if there are no new features to show
* Changed to use changes.json, track user last viewed, added ui test
* Fix UserManager unit tests broken by new ts_changes_viewed user field
* Moved getChanges to separate helper class, added unit test, added user view access check
* Updated to add new changes table and populate only on plugin update/install
* Added missing fixture class, updated UI screenshots
* Updated matomo font to add ringing bell and new releases icons
* Fix for integration test
* Reworked class structure, removed unnecessary angular directive, merged templates, other tidy ups
* built vue files
* built vue files
* Added null user check, missing table exception handling, show plugin name in change title, better handling of missing change fields
* Added sample changes file, moved UserChanges db code to changes model, added return type hints, better db error code handling, various other improvements
* Revert accidental UI screenshot commit
* Fix for incorrect link name parameter in sample changes, switched back to using $db->query for INSERT IGNORE
* Integration test fix, UI screenshot updates
* Test fix
* Added link styling, show CoreHome changes without plugin prefix in title
* Update UI test screenshot
* Added styles to the popover, added event for filtering changes
* Test fix
* UI test screenshot updates
Co-authored-by: sgiehl <stefan@matomo.org>
Co-authored-by: bx80 <bx80@users.noreply.github.com>
* Update test translation (#18531)
update a test failed XML
* updates all submodules (#18541)
Co-authored-by: diosmosis <diosmosis@users.noreply.github.com>
* Translations update from Hosted Weblate (#18529)
* Translated using Weblate (Greek)
Currently translated at 100.0% (162 of 162 strings)
Translation: Matomo/Plugin CoreAdminHome
Translate-URL: https://hosted.weblate.org/projects/matomo/plugin-coreadminhome/el/
[ci skip]
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Vasilis Lourdas <dev@lourdas.eu>
* Translated using Weblate (Chinese (Simplified))
Currently translated at 83.9% (136 of 162 strings)
Translation: Matomo/Plugin CoreAdminHome
Translate-URL: https://hosted.weblate.org/projects/matomo/plugin-coreadminhome/zh_Hans/
[ci skip]
Translated using Weblate (Chinese (Simplified))
Currently translated at 99.6% (620 of 622 strings)
Translation: Matomo/Matomo Base
Translate-URL: https://hosted.weblate.org/projects/matomo/matomo-base/zh_Hans/
[ci skip]
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 刘韬 <lyuutau@outlook.com>
* Update translation files
Updated by "Squash Git commits" hook in Weblate.
Translation: Matomo/Plugin CoreAdminHome
Translate-URL: https://hosted.weblate.org/projects/matomo/plugin-coreadminhome/
[ci skip]
Co-authored-by: Vasilis Lourdas <dev@lourdas.eu>
Co-authored-by: 刘韬 <lyuutau@outlook.com>
* [Vue] migrate report export directive and popover (#18440)
* update files
* sidenav start
* make getRef a utility method
* tweak
* add return type
* finish converting side-nav directive
* starting on reporting menu conversion
* remove unused properties
* convert reporting pages service
* migrate report metadata store
* remove angularjs files
* migrating reporting pages store
* make store adapters more immutable
* get service adapters to work
* fix a UI test
* another html fix
* migrate most of reporting menu directive and model
* Use themed font family for input forms to override materialize.css styling
* rebuild vue
* add a missing div
* ui test fixes
* update styling
* get to build
* get to load in the UI w/o error
* clone result of functions
* fix compile issue
* migrate widget loader and get to load in UI
* rebuild vue
* migrate widgetcontainer
* migrate widget bydimension container
* migrate widget + add tooltips directive
* quick fix
* Updating version to 4.6.0
* loading in page
* update expected screenshot
* add wait just in case travis is slow
* fix ordering bug
* add another wait
* rebuild vue
* css tweak
* fix some bugs and tests
* undo screenshot changes
* Menus test passing locally
* [Vue] date picker viewDate property is not kept up to date (#18385)
* viewDate ref is not kept up to date
* rebuild corehome
* reporting menu subcategory items are meant to be normal links
* update some screenshots
* use innerText instead of text() since angularjs maintains newlines in HTML that vue does not add
* trigger angularjs digest after ajaxhelper request
* rebuild vue
* update screenshots, fix bug in link generation in reporting menu and allow syncing multiple screenshot regexes at a time
* undo box-shadow change for UI tests
* fix more issues & update more tests
* update some screenshots
* fix some tests
* rebuild CoreHome
* quick fix
* built vue files
* fix angularjs issue
* add comment
* update umd files
* 4.6.1-rc1
* 4.6.1
* fix field array title
* apply some pr feedback
* apply more pr feedback
* another fix
* tweak
* fix ng-change not executed before ng-model
* fix another set of issues
* fix another issue
* rebuild vue
* better ng-change/ng-model fix
* update some screenshots
* rebuild vue
* remove some TODOs
* initiate initial ng-change ONLY for site selectors where this behavior applies
* emit/broadcast on correct scope in wrapper
* rebuild vue
* fix some issues
* couple more fixes
* fix another title issue
* rebuild vue
* do not report on ajax errors in notifications if not logged in
* migrate reporting page and model
* rebuild vue
* create sites selector model adapter
* fix siteselector vue bug, initial site is only set if there is just one site available
* rebuild vue
* migrate plugin settings directive
* remove TODO
* migrate plugin filter directive
* migrate two more plugins directives
* migrate save button
* fix a bunch of bugs
* fix another widget bug
* allow change event name between angularjs and vue
* rebuild vue
* migrate plugin form directive
* get to work
* migrate select-on-focus directive and start migrating report-export directive
* finish migrating report export directive & popover component + create reusable function to create vue app and add globals to it
* rebuild vue
* remove angularjs files and move less contents to vue dir
* built vue files
* fix function signature
* fix vue warning
* fix ajax request race condition
* rebuild vue
* add new notification type "help" so the help notification is not cleared when clearing transient notifications
* fix some bugs and tests
* update screenshot
* update screenshot & fix a test
* allow using unminified jquery ui + fix bug in last fix
* fix error when enrichedheadline is used in modal
* add polyfill min.js
* remove two todos
* fix widget url logic
* update some screenshots and fix sanitization/escape issue
* update screenshots
* rebuild vue
* fix url location updating regression in MatomoUrl.updateLocation use
* submodule
* update screenshots and fix possible error in json parse
* built vue files
* Merge branch 'vue-period-selector-regression' into vue-reporting-menu
* rebuild vue
* use correct variable
* rebuild vue
* fix widget url logic
* segment parameter can be undefined now for some reason
* fix ngmodel binding in siteselector adapter (for last time hopefully)
* the original site selector only set the first site to the first site in the initial sites query if there was only one site in the entire matomo instance
* fix sitesmanager ui test failure
* fix usersettings test failure
* rebuild vue
* more siteselector tweaks.
* build CoreHome
* more siteselector tweaks.
* another siteselector issue
* update screenshots
* update screenshot and try to fix random failure
* fix some issues in widget.vue when containerid is specified
* fix couple tests
* fix several test failures
* fix string concat
* fix test failure
* extra change
* fix last change and random failure
* styling fix
* fix last fix
* real fix this time
* fix stray request
* proper fix
* update build files
* try to fix random failure
* do not submit form
* check for api errors in promise chain in ajaxhelper.ts
* force a digest after a location change
* use proper abortcontroller method instead of promise hack, have to add new polyfill + try to fix random test failure
* some UI test fixes
* fix some report export issues
* several save button fixes + make replace approximation in createAngularJsAdapter better
* apply after manual click triggering in savebutton
* add names to divs so they can still be queried as they were in angularjs
* rebuild vue
* now that format_metrics checkbox works, need to check it
* fix unintended changes
* updated expected screenshots
* update two more
* go back to previous format_metrics behavior in popover
Co-authored-by: Justin Velluppillai <justin@innocraft.com>
Co-authored-by: justinvelluppillai <justinvelluppillai@users.noreply.github.com>
Co-authored-by: Matthieu Aubry <mattab@users.noreply.github.com>
* [Vue] remove support in vue for FormField.allSettings (#18542)
* deprecate support in vue for FormField.allSettings since deep watching the property doesnt quite work
* built vue files
* update screenshots
* update screenshot
* Show a summary of new features (#18065)
* Added "What is new" notification display, populated by a new event
* Removed test example event hook
* Added support for applying a link attribute to menu items, fixes layout issue for mobile with html menu items
* Updated UI test screenshots
* Revert accidental edit
* Hide the "What's new" icon if there are no new features to show
* Changed to use changes.json, track user last viewed, added ui test
* Fix UserManager unit tests broken by new ts_changes_viewed user field
* Moved getChanges to separate helper class, added unit test, added user view access check
* Updated to add new changes table and populate only on plugin update/install
* Added missing fixture class, updated UI screenshots
* Updated matomo font to add ringing bell and new releases icons
* Fix for integration test
* Reworked class structure, removed unnecessary angular directive, merged templates, other tidy ups
* built vue files
* built vue files
* Added null user check, missing table exception handling, show plugin name in change title, better handling of missing change fields
* Added sample changes file, moved UserChanges db code to changes model, added return type hints, better db error code handling, various other improvements
* Revert accidental UI screenshot commit
* Fix for incorrect link name parameter in sample changes, switched back to using $db->query for INSERT IGNORE
* Integration test fix, UI screenshot updates
* Test fix
* Added link styling, show CoreHome changes without plugin prefix in title
* Update UI test screenshot
* Added styles to the popover, added event for filtering changes
* Test fix
* UI test screenshot updates
Co-authored-by: sgiehl <stefan@matomo.org>
Co-authored-by: bx80 <bx80@users.noreply.github.com>
* Update test translation (#18531)
update a test failed XML
* updates all submodules (#18541)
Co-authored-by: diosmosis <diosmosis@users.noreply.github.com>
* Translations update from Hosted Weblate (#18529)
* Translated using Weblate (Greek)
Currently translated at 100.0% (162 of 162 strings)
Translation: Matomo/Plugin CoreAdminHome
Translate-URL: https://hosted.weblate.org/projects/matomo/plugin-coreadminhome/el/
[ci skip]
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Vasilis Lourdas <dev@lourdas.eu>
* Translated using Weblate (Chinese (Simplified))
Currently translated at 83.9% (136 of 162 strings)
Translation: Matomo/Plugin CoreAdminHome
Translate-URL: https://hosted.weblate.org/projects/matomo/plugin-coreadminhome/zh_Hans/
[ci skip]
Translated using Weblate (Chinese (Simplified))
Currently translated at 99.6% (620 of 622 strings)
Translation: Matomo/Matomo Base
Translate-URL: https://hosted.weblate.org/projects/matomo/matomo-base/zh_Hans/
[ci skip]
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 刘韬 <lyuutau@outlook.com>
* Update translation files
Updated by "Squash Git commits" hook in Weblate.
Translation: Matomo/Plugin CoreAdminHome
Translate-URL: https://hosted.weblate.org/projects/matomo/plugin-coreadminhome/
[ci skip]
Co-authored-by: Vasilis Lourdas <dev@lourdas.eu>
Co-authored-by: 刘韬 <lyuutau@outlook.com>
* [Vue] migrate report export directive and popover (#18440)
* update files
* sidenav start
* make getRef a utility method
* tweak
* add return type
* finish converting side-nav directive
* starting on reporting menu conversion
* remove unused properties
* convert reporting pages service
* migrate report metadata store
* remove angularjs files
* migrating reporting pages store
* make store adapters more immutable
* get service adapters to work
* fix a UI test
* another html fix
* migrate most of reporting menu directive and model
* Use themed font family for input forms to override materialize.css styling
* rebuild vue
* add a missing div
* ui test fixes
* update styling
* get to build
* get to load in the UI w/o error
* clone result of functions
* fix compile issue
* migrate widget loader and get to load in UI
* rebuild vue
* migrate widgetcontainer
* migrate widget bydimension container
* migrate widget + add tooltips directive
* quick fix
* Updating version to 4.6.0
* loading in page
* update expected screenshot
* add wait just in case travis is slow
* fix ordering bug
* add another wait
* rebuild vue
* css tweak
* fix some bugs and tests
* undo screenshot changes
* Menus test passing locally
* [Vue] date picker viewDate property is not kept up to date (#18385)
* viewDate ref is not kept up to date
* rebuild corehome
* reporting menu subcategory items are meant to be normal links
* update some screenshots
* use innerText instead of text() since angularjs maintains newlines in HTML that vue does not add
* trigger angularjs digest after ajaxhelper request
* rebuild vue
* update screenshots, fix bug in link generation in reporting menu and allow syncing multiple screenshot regexes at a time
* undo box-shadow change for UI tests
* fix more issues & update more tests
* update some screenshots
* fix some tests
* rebuild CoreHome
* quick fix
* built vue files
* fix angularjs issue
* add comment
* update umd files
* 4.6.1-rc1
* 4.6.1
* fix field array title
* apply some pr feedback
* apply more pr feedback
* another fix
* tweak
* fix ng-change not executed before ng-model
* fix another set of issues
* fix another issue
* rebuild vue
* better ng-change/ng-model fix
* update some screenshots
* rebuild vue
* remove some TODOs
* initiate initial ng-change ONLY for site selectors where this behavior applies
* emit/broadcast on correct scope in wrapper
* rebuild vue
* fix some issues
* couple more fixes
* fix another title issue
* rebuild vue
* do not report on ajax errors in notifications if not logged in
* migrate reporting page and model
* rebuild vue
* create sites selector model adapter
* fix siteselector vue bug, initial site is only set if there is just one site available
* rebuild vue
* migrate plugin settings directive
* remove TODO
* migrate plugin filter directive
* migrate two more plugins directives
* migrate save button
* fix a bunch of bugs
* fix another widget bug
* allow change event name between angularjs and vue
* rebuild vue
* migrate plugin form directive
* get to work
* migrate select-on-focus directive and start migrating report-export directive
* finish migrating report export directive & popover component + create reusable function to create vue app and add globals to it
* rebuild vue
* remove angularjs files and move less contents to vue dir
* built vue files
* fix function signature
* fix vue warning
* fix ajax request race condition
* rebuild vue
* add new notification type "help" so the help notification is not cleared when clearing transient notifications
* fix some bugs and tests
* update screenshot
* update screenshot & fix a test
* allow using unminified jquery ui + fix bug in last fix
* fix error when enrichedheadline is used in modal
* add polyfill min.js
* remove two todos
* fix widget url logic
* update some screenshots and fix sanitization/escape issue
* update screenshots
* rebuild vue
* fix url location updating regression in MatomoUrl.updateLocation use
* submodule
* update screenshots and fix possible error in json parse
* built vue files
* Merge branch 'vue-period-selector-regression' into vue-reporting-menu
* rebuild vue
* use correct variable
* rebuild vue
* fix widget url logic
* segment parameter can be undefined now for some reason
* fix ngmodel binding in siteselector adapter (for last time hopefully)
* the original site selector only set the first site to the first site in the initial sites query if there was only one site in the entire matomo instance
* fix sitesmanager ui test failure
* fix usersettings test failure
* rebuild vue
* more siteselector tweaks.
* build CoreHome
* more siteselector tweaks.
* another siteselector issue
* update screenshots
* update screenshot and try to fix random failure
* fix some issues in widget.vue when containerid is specified
* fix couple tests
* fix several test failures
* fix string concat
* fix test failure
* extra change
* fix last change and random failure
* styling fix
* fix last fix
* real fix this time
* fix stray request
* proper fix
* update build files
* try to fix random failure
* do not submit form
* check for api errors in promise chain in ajaxhelper.ts
* force a digest after a location change
* use proper abortcontroller method instead of promise hack, have to add new polyfill + try to fix random test failure
* some UI test fixes
* fix some report export issues
* several save button fixes + make replace approximation in createAngularJsAdapter better
* apply after manual click triggering in savebutton
* add names to divs so they can still be queried as they were in angularjs
* rebuild vue
* now that format_metrics checkbox works, need to check it
* fix unintended changes
* updated expected screenshots
* update two more
* go back to previous format_metrics behavior in popover
Co-authored-by: Justin Velluppillai <justin@innocraft.com>
Co-authored-by: justinvelluppillai <justinvelluppillai@users.noreply.github.com>
Co-authored-by: Matthieu Aubry <mattab@users.noreply.github.com>
* [Vue] remove support in vue for FormField.allSettings (#18542)
* deprecate support in vue for FormField.allSettings since deep watching the property doesnt quite work
* built vue files
* update screenshots
* update screenshot
* fix tests
* rebuild
* rebuild
* order plugins by dependencies in vue:build and fix warning in corehome build
* built vue files
* built vue files
* remove unused imports
* built vue files
* remove multilinefield component, fieldtextareaarray does the same thing
* edit-trigger is not used anywhere
* migrate sitetypes model to store
* do not load nonexistant files
* remove reference nonexistant files
* start converting sitefields component
* more work on sitefields component
* undo submodule change
* rebuild
* get sitesmanager to build
* get SiteFields component to work in UI
* datepicker does not format times
* export other stores
* fix some typing issues and rebuild
* start on site management conversion
* add more comma delimited props to list + remove controller JS
* rebuild
* convert sites manager controller to sitesmanagement component
* remove TODOs
* finish migrating sitesmanager
* remove some TODO
* get to build
* fixes from testing
* rebuild
* rebuild and fix issue w/ globalsettings hash detection
* migrate capabilities-edit component.
* some fixes and get to build
* get to work
* built vue files
* get to work and rebuild
* migrate user edit form component
* some fixes
* fixes
* another fix
* more fixes
* update file
* more fixes
* fix ref
* rebuild vue
* couple more fixes
* migrate paged users list and get to build
* fixing issues
* workaround vue issue w/ directives that modify css classes on elements that also bind to :class
* dropdownmenu directive should be aware of data-target parameter that is required by materialize
* handle disabled options in fieldselect
* fix issues and rebuild vue
* migrate usersmanager component and get to build
* forgot to add files, fix some issues + rebuild
* migrate usersmanager controllers and twig template parts
* fix compile issues and get to build
* fix issues and rebuild
* fix bug and rebuild
* fix bug and rebuild
* fix issue
* fix issues and rebuild
* fix ui test
* fix UI test failure
* fixing some issues
* complete fixes
* fix some more issues
* fix ui test failures
* another fix
* several more fixes
* fix delete dialog
* more fixes
* fix styling issue
* more fixes
* fix another ui test + update other UI tests
* fixing edisiteid handling
* update screenshots
* fix UI tests somre more
* fix random failure
* fixes
* reference css class not attribute (since that is what is added in vue)
* fixing more ui tests
* try to fix vue css class in directive issue
* tweak
* in groupedsetting handle templateFile property for angularjs BC
* rebuild vue
* fix view tracking code link
* fixing UI tests
* fix selector in test for this branch only
* Update screenshot.
* update screenshot
* update screenshots
* style fix
* fix selectors and update screenshot
* built vue files
* Update screenshot + fix title and spacing.
* fix password changing
* fixing tests
* fix more issues
* fix styling
* built vue files
* more fixes
* more styling fixes
* more fixes
* Fix tests locally.
* Fixing more issues + getting UI tests to pass locally.
* update tagmanger module?
* fix UI tests
* remove unneeded event
* update screenshots
* start migrating series-picker
* get series picker component to work
* start migrating single metric view
* update style
* fix some issues
* get to work in UI
* fix percent evolution
* fix some UI tests
* built vue files
* update screenshots
Co-authored-by: Ben Burgess <88810029+bx80@users.noreply.github.com>
Co-authored-by: sgiehl <stefan@matomo.org>
Co-authored-by: bx80 <bx80@users.noreply.github.com>
Co-authored-by: Peter Zhang <peter@innocraft.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Weblate (bot) <hosted@weblate.org>
Co-authored-by: Vasilis Lourdas <dev@lourdas.eu>
Co-authored-by: 刘韬 <lyuutau@outlook.com>
Co-authored-by: Justin Velluppillai <justin@innocraft.com>
Co-authored-by: justinvelluppillai <justinvelluppillai@users.noreply.github.com>
Co-authored-by: Matthieu Aubry <mattab@users.noreply.github.com>
Diffstat (limited to 'plugins')
28 files changed, 1610 insertions, 596 deletions
diff --git a/plugins/CoreHome/tests/UI/SingleMetricView_spec.js b/plugins/CoreHome/tests/UI/SingleMetricView_spec.js index 93b1959894..d0722973b7 100644 --- a/plugins/CoreHome/tests/UI/SingleMetricView_spec.js +++ b/plugins/CoreHome/tests/UI/SingleMetricView_spec.js @@ -38,7 +38,7 @@ describe('SingleMetricView', function () { $('#dashboardWidgetsArea #widgetCoreVisualizationssingleMetricViewcolumn .jqplot-seriespicker').trigger('mouseenter'); }); await page.webpage.evaluate(function(){ - $('#dashboardWidgetsArea .jqplot-seriespicker-popover label:contains(Revenue)').click(); + $('#dashboardWidgetsArea .jqplot-seriespicker-popover label:contains(Revenue):eq(0)').click(); }); await page.waitForNetworkIdle(); await page.waitForTimeout(250); @@ -53,7 +53,7 @@ describe('SingleMetricView', function () { }); await page.waitForTimeout(250); await page.evaluate(function(){ - $('#dashboardWidgetsArea .jqplot-seriespicker-popover label:contains(_x)').click() + $('#dashboardWidgetsArea .jqplot-seriespicker-popover label:contains(_x):eq(0)').click() }); await page.waitForNetworkIdle(); await page.waitForTimeout(250); @@ -69,7 +69,7 @@ describe('SingleMetricView', function () { }); await page.waitForTimeout(250); await page.evaluate(function(){ - $('#dashboardWidgetsArea #widgetCoreVisualizationssingleMetricViewcolumn .jqplot-seriespicker-popover label:contains(Revenue)').click() + $('#dashboardWidgetsArea #widgetCoreVisualizationssingleMetricViewcolumn .jqplot-seriespicker-popover label:contains(Revenue):eq(0)').click() }); await page.waitForNetworkIdle(); await page.waitForTimeout(250); diff --git a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_formatted_metric.png b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_formatted_metric.png index 26ce8b42b5..6f6a0b3397 100644 --- a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_formatted_metric.png +++ b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_formatted_metric.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb9305159cdcbf107a6747b315cba146214a1f73f404c200aa37d6734706ccc2 -size 6485 +oid sha256:f52ffb459eaad6bf566e3f837974b82f02ef104a484d16149b3e8f204f6a220f +size 6302 diff --git a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_goal_metric.png b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_goal_metric.png index e6cdfa9a26..668b981e43 100644 --- a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_goal_metric.png +++ b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_goal_metric.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33bbb2c1fe617afaf7dc2216e981057698abe7679814ca3d4a729517b7859b33 -size 8952 +oid sha256:d7eae513738ddda333cabbf469c1acadb3ac3bc4f7ed80caa0520b0a73b23dfb +size 9002 diff --git a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_loaded.png b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_loaded.png index 9dcc86fc15..2d0189601c 100644 --- a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_loaded.png +++ b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_loaded.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da10b7861b5b8208164116aebb716bb8d6028701544c7430bf172d9b328fbe74 -size 4741 +oid sha256:e8d3f4bcf5e2b039f91160466eb94f26f54f24d57d03188cce70132795789609 +size 4646 diff --git a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_range.png b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_range.png index f685b2dc05..97a4a0938c 100644 --- a/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_range.png +++ b/plugins/CoreHome/tests/UI/expected-screenshots/SingleMetricView_range.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cbbbee4066bb4ae19015e8398353d512f42d943cd27a375554218f865581738 -size 5059 +oid sha256:307d7efaa78defa78c7162bae0e51beb7d8d963db529ab5f4a95153f339c2fd3 +size 4844 diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php index 095253612d..a2f0c18205 100644 --- a/plugins/CoreVisualizations/CoreVisualizations.php +++ b/plugins/CoreVisualizations/CoreVisualizations.php @@ -39,8 +39,8 @@ class CoreVisualizations extends \Piwik\Plugin public function getStylesheetFiles(&$stylesheets) { - $stylesheets[] = "plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.less"; - $stylesheets[] = "plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.less"; + $stylesheets[] = "plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.less"; + $stylesheets[] = "plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.less"; $stylesheets[] = "plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less"; $stylesheets[] = "plugins/CoreVisualizations/stylesheets/jqplot.css"; @@ -48,8 +48,6 @@ class CoreVisualizations extends \Piwik\Plugin public function getJsFiles(&$jsFiles) { - $jsFiles[] = "plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.js"; - $jsFiles[] = "plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.js"; $jsFiles[] = "plugins/CoreVisualizations/javascripts/seriesPicker.js"; $jsFiles[] = "plugins/CoreVisualizations/javascripts/jqplot.js"; diff --git a/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.html b/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.html deleted file mode 100644 index cfd36998dc..0000000000 --- a/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.html +++ /dev/null @@ -1,53 +0,0 @@ -<div - class="jqplot-seriespicker" - ng-class="{open: $ctrl.isPopupVisible}" - ng-mouseenter="$ctrl.isPopupVisible = true" - ng-mouseleave="$ctrl.onLeavePopup()" -> - <a - href="#" - ng-click="$event.preventDefault(); $event.stopPropagation();" - > - + - </a> - <div - class="jqplot-seriespicker-popover" - ng-if="$ctrl.isPopupVisible" - > - <p class="headline">{{ ($ctrl.multiselect ? 'General_MetricsToPlot' : 'General_MetricToPlot') | translate }}</p> - <p - ng-repeat="columnConfig in $ctrl.selectableColumns" - class="pickColumn" - ng-click="$ctrl.optionSelected(columnConfig.column, $ctrl.columnStates)" - > - <label> - <input - class="select" - ng-checked="$ctrl.columnStates[columnConfig.column]" - ng-attr-type="{{ $ctrl.multiselect ? 'checkbox' : 'radio' }}" - /> - <span>{{ columnConfig.translation }}</span> - </label> - </p> - <p - ng-if="$ctrl.selectableRows.length" - class="headline recordsToPlot" - > - {{ 'General_RecordsToPlot' | translate }} - </p> - <p - ng-repeat="rowConfig in $ctrl.selectableRows" - class="pickRow" - ng-click="$ctrl.optionSelected(rowConfig.matcher, $ctrl.rowStates)" - > - <label> - <input - class="select" - ng-checked="$ctrl.rowStates[rowConfig.matcher]" - ng-attr-type="{{ $ctrl.multiselect ? 'checkbox' : 'radio' }}" - /> - <span>{{ rowConfig.label }}</span> - </label> - </p> - </div> -</div>
\ No newline at end of file diff --git a/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.js b/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.js deleted file mode 100644 index bbfeb9444c..0000000000 --- a/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.js +++ /dev/null @@ -1,142 +0,0 @@ -/*! - * Matomo - free/libre analytics platform - * - * @link https://matomo.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - */ - -/** - * This series picker component is a popup that displays a list of metrics/row - * values that can be selected. It's used by certain datatable visualizations - * to allow users to select different data series for display. - * - * Inputs: - * - multiselect: true if the picker should allow selecting multiple items, false - * if otherwise. - * - selectableColumns: the list of selectable metric values. must be a list of - * objects with the following properties: - * * column: the ID of the column, eg, nb_visits - * * translation: the translated text for the column, eg, Visits - * - selectableRows: the list of selectable row values. must be a list of objects - * with the following properties: - * * matcher: the ID of the row - * * label: the display text for the row - * - selectedColumns: the list of selected columns. should be a list of strings - * that correspond to the 'column' property in selectableColumns. - * - selectedRows: the list of selected rows. should be a list of strings that - * correspond to the 'matcher' property in selectableRows. - * - onSelect: expression invoked when a user makes a new selection. invoked - * with the following local variables: - * * columns: list of IDs of new selected columns, if any - * * rows: list of matchers of new selected rows, if any - * - * Usage: - * <piwik-series-picker /> - */ -(function () { - angular.module('piwikApp').component('piwikSeriesPicker', { - templateUrl: 'plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.html?cb=' + piwik.cacheBuster, - bindings: { - multiselect: '<', - selectableColumns: '<', - selectableRows: '<', - selectedColumns: '<', - selectedRows: '<', - onSelect: '&' - }, - controller: SeriesPickerController - }); - - SeriesPickerController.$inject = []; - - function SeriesPickerController() { - var vm = this; - vm.isPopupVisible = false; - - // note: column & row states are separated since it's technically possible (though - // highly improbable) that a row value matcher will be the same as a recognized column. - vm.columnStates = {}; - vm.rowStates = {}; - vm.optionSelected = optionSelected; - vm.onLeavePopup = onLeavePopup; - vm.$onInit = $onInit; - - function $onInit() { - vm.columnStates = getInitialOptionStates(vm.selectableColumns, vm.selectedColumns); - vm.rowStates = getInitialOptionStates(vm.selectableRows, vm.selectedRows); - } - - function getInitialOptionStates(allOptions, selectedOptions) { - var states = {}; - - allOptions.forEach(function (columnConfig) { - states[columnConfig.column || columnConfig.matcher] = false; - }); - - selectedOptions.forEach(function (column) { - states[column] = true; - }); - - return states; - } - - function optionSelected(optionValue, optionStates) { - if (!vm.multiselect) { - unselectOptions(vm.columnStates); - unselectOptions(vm.rowStates); - } - - optionStates[optionValue] = !optionStates[optionValue]; - - triggerOnSelectAndClose(); - } - - function onLeavePopup() { - vm.isPopupVisible = false; - - if (optionsChanged()) { - triggerOnSelectAndClose(); - } - } - - function triggerOnSelectAndClose() { - if (!vm.onSelect) { - return; - } - - vm.isPopupVisible = false; - - vm.onSelect({ - columns: getSelected(vm.columnStates), - rows: getSelected(vm.rowStates) - }); - } - - function optionsChanged() { - return !arrayEqual(getSelected(vm.columnStates), vm.selectedColumns) - || !arrayEqual(getSelected(vm.rowStates), vm.selectedRows); - } - - function arrayEqual(lhs, rhs) { - if (lhs.length !== rhs.length) { - return false; - } - - return lhs - .filter(function (element) { return rhs.indexOf(element) === -1; }) - .length === 0; - } - - function unselectOptions(optionStates) { - Object.keys(optionStates).forEach(function (optionName) { - optionStates[optionName] = false; - }); - } - - function getSelected(optionStates) { - return Object.keys(optionStates).filter(function (optionName) { - return !! optionStates[optionName]; - }); - } - } -})();
\ No newline at end of file diff --git a/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.less b/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.less deleted file mode 100644 index 9d4fdc8de9..0000000000 --- a/plugins/CoreVisualizations/angularjs/series-picker/series-picker.component.less +++ /dev/null @@ -1,28 +0,0 @@ -piwik-series-picker { - display: inline-block; - - .jqplot-seriespicker { - &:not(.open) { - opacity: .55; - } - - &.open { // while open, make sure we're above other series picker icons - z-index: 1000; - } - - > a { - display: inline-block; - opacity: 0; - position: absolute; - } - - position: relative; - } - - .jqplot-seriespicker-popover { - position: absolute; - - top: -3px; - left: -4px; - } -} diff --git a/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.html b/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.html deleted file mode 100644 index e302dda171..0000000000 --- a/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.html +++ /dev/null @@ -1,20 +0,0 @@ -<div class="singleMetricView" ng-class="{'loading': $ctrl.isLoading}"> - <piwik-sparkline - class="metric-sparkline" - params="$ctrl.sparklineParams" - > - </piwik-sparkline> - <div class="metric-value"> - <span title="{{ $ctrl.metricDocumentation }}"> - <strong>{{ $ctrl.metricValue }}</strong> {{ ($ctrl.metricTranslation || '').toLowerCase() }} - </span> - <span class="metricEvolution" - ng-if="$ctrl.pastValue !== null" - title="{{ 'General_EvolutionSummaryGeneric'|translate:$ctrl.metricValue:$ctrl.getCurrentPeriod():$ctrl.pastValue:$ctrl.pastPeriod:$ctrl.metricChangePercent }}" - > - <span ng-class="{'positive-evolution': $ctrl.metricValueUnformatted > $ctrl.pastValueUnformatted, 'negative-evolution': $ctrl.metricValueUnformatted < $ctrl.pastValueUnformatted}"> - {{ $ctrl.metricChangePercent }} - </span> - </span> - </div> -</div>
\ No newline at end of file diff --git a/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.js b/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.js deleted file mode 100644 index 2c3b19aff7..0000000000 --- a/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.js +++ /dev/null @@ -1,279 +0,0 @@ -/*! - * Matomo - free/libre analytics platform - * - * @link https://matomo.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - */ - -/** - * Usage: - * <piwik-single-metric-view> - */ -(function () { - angular.module('piwikApp').component('piwikSingleMetricView', { - templateUrl: 'plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.html?cb=' + piwik.cacheBuster, - bindings: { - metric: '<', - idGoal: '<', - metricTranslations: '<', - metricDocumentations: '<', - goals: '<', - goalMetrics: '<' - }, - controller: SingleMetricViewController - }); - - SingleMetricViewController.$inject = ['piwik', 'piwikApi', '$element', '$httpParamSerializer', '$compile', '$scope', 'piwikPeriods', '$q']; - - function SingleMetricViewController(piwik, piwikApi, $element, $httpParamSerializer, $compile, $scope, piwikPeriods, $q) { - var seriesPickerScope; - - var vm = this; - vm.metricValue = null; - vm.isLoading = false; - vm.metricTranslation = null; - vm.metricDocumentation = null; - vm.selectableColumns = []; - vm.responses = null; - vm.sparklineParams = {}; - vm.$onInit = $onInit; - vm.$onChanges = $onChanges; - vm.$onDestroy = $onDestroy; - vm.getCurrentPeriod = getCurrentPeriod; - vm.getMetricTranslation = getMetricTranslation; - vm.setMetric = setMetric; - - function setSparklineParams() { - var params = { module: 'API', action: 'get', columns: vm.metric }; - if (isIdGoalSet()) { - params.idGoal = vm.idGoal; - params.module = 'Goals'; - } - vm.sparklineParams = params; - } - - function $onInit() { - vm.selectedColumns = [vm.metric]; - if (piwik.period !== 'range') { - vm.pastPeriod = getPastPeriodStr(); - } - - setSelectableColumns(); - - createSeriesPicker(); - - $element.closest('.widgetContent') - .on('widget:destroy', function() { $scope.$parent.$destroy(); }) - .on('widget:reload', function() { $scope.$parent.$destroy(); }); - - setSparklineParams(); - } - - function $onChanges(changes) { - if (changes.metric && changes.metric.previousValue !== changes.metric.currentValue) { - onMetricChanged(); - } - } - - function $onDestroy() { - $element.closest('.widgetContent').off('widget:destroy').off('widget:reload'); - destroySeriesPicker(); - } - - function fetchData() { - vm.isLoading = true; - - var promises = []; - - var apiModule = 'API'; - var apiAction = 'get'; - - var extraParams = {}; - if (isIdGoalSet()) { - extraParams.idGoal = vm.idGoal; - // the conversion rate added by the AddColumnsProcessedMetrics filter conflicts w/ the goals one, so don't run it - extraParams.filter_add_columns_when_show_all_columns = 0; - - apiModule = 'Goals'; - apiAction = 'get'; - } - - // first request for formatted data - promises.push(piwikApi.fetch($.extend({ - method: apiModule + '.' + apiAction, - format_metrics: 'all' - }, extraParams))); - - if (piwik.period !== 'range') { - // second request for unformatted data so we can calculate evolution - promises.push(piwikApi.fetch($.extend({ - method: apiModule + '.' + apiAction, - format_metrics: '0' - }, extraParams))); - - // third request for past data (unformatted) - promises.push(piwikApi.fetch($.extend({ - method: apiModule + '.' + apiAction, - date: getLastPeriodDate(), - format_metrics: '0', - }, extraParams))); - - // fourth request for past data (formatted for tooltip display) - promises.push(piwikApi.fetch($.extend({ - method: apiModule + '.' + apiAction, - date: getLastPeriodDate(), - format_metrics: 'all', - }, extraParams))); - } - - return $q.all(promises).then(function (responses) { - vm.responses = responses; - vm.isLoading = false; - }); - } - - function recalculateValues() { - // update display based on processed report metadata - setWidgetTitle(); - vm.metricDocumentation = getMetricDocumentation(); - - // update data - var currentData = vm.responses[0]; - vm.metricValue = currentData[vm.metric] || 0; - - if (vm.responses[1]) { - vm.metricValueUnformatted = vm.responses[1][vm.metric]; - - var pastData = vm.responses[2]; - vm.pastValueUnformatted = pastData[vm.metric] || 0; - - var evolution = piwik.helper.calculateEvolution(vm.metricValueUnformatted, vm.pastValueUnformatted); - vm.metricChangePercent = (evolution * 100).toFixed(2) + ' %'; - - var pastDataFormatted = vm.responses[3]; - vm.pastValue = pastDataFormatted[vm.metric] || 0; - } else { - vm.pastValue = null; - vm.metricChangePercent = null; - } - - // don't change the metric translation until data is fetched to avoid loading state confusion - vm.metricTranslation = getMetricTranslation(); - } - - function getLastPeriodDate() { - var RangePeriod = piwikPeriods.get('range'); - var result = RangePeriod.getLastNRange(piwik.period, 2, piwik.currentDateString).startDate; - return piwikPeriods.format(result); - } - - function setWidgetTitle() { - var title = vm.getMetricTranslation(); - if (isIdGoalSet()) { - var goalName = vm.goals[vm.idGoal].name; - title = goalName + ' - ' + title; - } - - $element.closest('div.widget').find('.widgetTop > .widgetName > span').text(title); - } - - function getCurrentPeriod() { - if (piwik.startDateString === piwik.endDateString) { - return piwik.endDateString; - } - return piwik.startDateString + ', ' + piwik.endDateString; - } - - function createSeriesPicker() { - vm.selectedColumns = [vm.idGoal ? ('goal' + vm.idGoal + '_' + vm.metric) : vm.metric]; - - var $widgetName = $element.closest('div.widget').find('.widgetTop > .widgetName'); - - var $seriesPicker = $('<piwik-series-picker class="single-metric-view-picker" multiselect="false" ' + - 'selectable-columns="$ctrl.selectableColumns" selectable-rows="[]" selected-columns="$ctrl.selectedColumns" ' + - 'selected-rows="[]" on-select="$ctrl.setMetric(columns[0])" />'); - - seriesPickerScope = $scope.$new(); - $compile($seriesPicker)(seriesPickerScope); - - $widgetName.append($seriesPicker); - } - - function destroySeriesPicker() { - $element.closest('div.widget').find('.single-metric-view-picker').remove(); - - seriesPickerScope.$destroy(); - seriesPickerScope = null; - } - - function getMetricDocumentation() { - if (!vm.metricDocumentations || !vm.metricDocumentations[vm.metric]) { - return ''; - } - - return vm.metricDocumentations[vm.metric]; - } - - function getMetricTranslation() { - if (!vm.metricTranslations || !vm.metricTranslations[vm.metric]) { - return ''; - } - - return vm.metricTranslations[vm.metric]; - } - - function setSelectableColumns() { - var result = []; - Object.keys(vm.metricTranslations).forEach(function (column) { - result.push({ column: column, translation: vm.metricTranslations[column] }); - }); - - Object.keys(vm.goals).forEach(function (idgoal) { - var goal = vm.goals[idgoal]; - vm.goalMetrics.forEach(function (column) { - result.push({ - column: 'goal' + goal.idgoal + '_' + column, - translation: goal.name + ' - ' + vm.metricTranslations[column] - }); - }); - }); - - vm.selectableColumns = result; - } - - function onMetricChanged() { - setSparklineParams(); - - fetchData().then(recalculateValues); - - // notify widget of parameter change so it is replaced - $element.closest('[widgetId]').trigger('setParameters', { column: vm.metric, idGoal: vm.idGoal }); - } - - function setMetric(newColumn) { - var idGoal; - - var m = newColumn.match(/^goal([0-9]+)_(.*)/); - if (m) { - idGoal = +m[1]; - newColumn = m[2]; - } - - if (vm.metric !== newColumn || idGoal !== vm.idGoal) { - vm.metric = newColumn; - vm.idGoal = idGoal; - onMetricChanged(); - } - } - - function getPastPeriodStr() { - var startDate = piwikPeriods.get('range').getLastNRange(piwik.period, 2, piwik.currentDateString).startDate; - var dateRange = piwikPeriods.get(piwik.period).parse(startDate).getDateRange(); - return piwikPeriods.format(dateRange[0]) + ',' + piwikPeriods.format(dateRange[1]); - } - - function isIdGoalSet() { - return vm.idGoal || vm.idGoal === 0; - } - } -})(); diff --git a/plugins/CoreVisualizations/javascripts/seriesPicker.js b/plugins/CoreVisualizations/javascripts/seriesPicker.js index 2ca659445c..6ea90cc326 100644 --- a/plugins/CoreVisualizations/javascripts/seriesPicker.js +++ b/plugins/CoreVisualizations/javascripts/seriesPicker.js @@ -83,47 +83,48 @@ }); // initialize dom element - var seriesPicker = '<piwik-series-picker' - + ' multiselect="' + (this.multiSelect ? 'true' : 'false') + '"' - + ' selectable-columns="selectableColumns"' - + ' selectable-rows="selectableRows"' - + ' selected-columns="selectedColumns"' - + ' selected-rows="selectedRows"' - + ' on-select="selectionChanged(columns, rows)"/>'; - - this.domElem = $(seriesPicker); + this.domElem = $('<div style="display:inline-block"><div></div></div>'); $(this).trigger('placeSeriesPicker'); - piwikHelper.compileAngularComponents(this.domElem, { - params: { - selectableColumns: this.selectableColumns, - selectableRows: this.selectableRows, - selectedColumns: selectedColumns, - selectedRows: selectedRows, - selectionChanged: function selectionChanged(columns, rows) { - if (columns.length === 0 && rows.length === 0) { - return; - } - - rows = rows.map(encodeURIComponent); - - $(self).trigger('seriesPicked', [columns, rows]); - - // inform dashboard widget about changed parameters (to be restored on reload) - var UI = require('piwik/UI'); - var params = { - columns: columns, - columns_to_display: columns, - rows: rows, - rows_to_display: rows - }; - - var tableNode = $('#' + self.dataTableId); - UI.DataTable.prototype.notifyWidgetParametersChange(tableNode, params); + var createVNode = Vue.createVNode; + var createVueApp = CoreHome.createVueApp; + var SeriesPicker = CoreVisualizations.SeriesPicker; + + var app = createVueApp({ + render: function () { + return createVNode(SeriesPicker, { + multiselect: self.multiSelect, + selectableColumns: self.selectableColumns, + selectableRows: self.selectableRows, + selectedColumns: selectedColumns, + selectedRows: selectedRows, + onSelect: function selectionChanged(event) { + var columns = event.columns, rows = event.rows; + if (columns.length === 0 && rows.length === 0) { + return; } - } + + rows = rows.map(encodeURIComponent); + + $(self).trigger('seriesPicked', [columns, rows]); + + // inform dashboard widget about changed parameters (to be restored on reload) + var UI = require('piwik/UI'); + var params = { + columns: columns, + columns_to_display: columns, + rows: rows, + rows_to_display: rows + }; + + var tableNode = $('#' + self.dataTableId); + UI.DataTable.prototype.notifyWidgetParametersChange(tableNode, params); + } + }); + } }); + app.mount(this.domElem.children()[0]); function isItemDisplayed(columnOrRowConfig) { return columnOrRowConfig.displayed; diff --git a/plugins/CoreVisualizations/stylesheets/jqplot.css b/plugins/CoreVisualizations/stylesheets/jqplot.css index 2be3bda099..e2c7e60eb6 100644 --- a/plugins/CoreVisualizations/stylesheets/jqplot.css +++ b/plugins/CoreVisualizations/stylesheets/jqplot.css @@ -204,7 +204,6 @@ a.rowevolution-startmulti { .jqplot-seriespicker { display: block; - position: absolute; z-index: 9; width: 24px; height: 16px; diff --git a/plugins/CoreVisualizations/vue/dist/CoreVisualizations.umd.js b/plugins/CoreVisualizations/vue/dist/CoreVisualizations.umd.js new file mode 100644 index 0000000000..2299cdb54d --- /dev/null +++ b/plugins/CoreVisualizations/vue/dist/CoreVisualizations.umd.js @@ -0,0 +1,790 @@ +(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["CoreVisualizations"] = factory(require("CoreHome"), require("vue")); + else + root["CoreVisualizations"] = 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/CoreVisualizations/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__; + +/***/ }), + +/***/ "8bbf": +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__8bbf__; + +/***/ }), + +/***/ "fae3": +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +// ESM COMPAT FLAG +__webpack_require__.r(__webpack_exports__); + +// EXPORTS +__webpack_require__.d(__webpack_exports__, "SeriesPicker", function() { return /* reexport */ SeriesPicker; }); +__webpack_require__.d(__webpack_exports__, "SingleMetricView", function() { return /* reexport */ SingleMetricView; }); + +// 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 "CoreHome" +var external_CoreHome_ = __webpack_require__("19dc"); + +// 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--12-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--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue?vue&type=template&id=bd202f38 + +var _hoisted_1 = { + key: 0, + class: "jqplot-seriespicker-popover" +}; +var _hoisted_2 = { + class: "headline" +}; +var _hoisted_3 = ["onClick"]; +var _hoisted_4 = ["type", "checked"]; +var _hoisted_5 = { + key: 0, + class: "headline recordsToPlot" +}; +var _hoisted_6 = ["onClick"]; +var _hoisted_7 = ["type", "checked"]; +function SeriesPickervue_type_template_id_bd202f38_render(_ctx, _cache, $props, $setup, $data, $options) { + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", { + class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(["jqplot-seriespicker", { + open: _ctx.isPopupVisible + }]), + onMouseenter: _cache[1] || (_cache[1] = function ($event) { + return _ctx.isPopupVisible = true; + }), + onMouseleave: _cache[2] || (_cache[2] = function ($event) { + return _ctx.onLeavePopup(); + }) + }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", { + href: "#", + onClick: _cache[0] || (_cache[0] = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withModifiers"])(function () {}, ["prevent", "stop"])) + }, " + "), _ctx.isPopupVisible ? (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"])("p", _hoisted_2, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate(_ctx.multiselect ? 'General_MetricsToPlot' : 'General_MetricToPlot')), 1), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.selectableColumns, function (columnConfig) { + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("p", { + class: "pickColumn", + onClick: function onClick($event) { + return _ctx.optionSelected(columnConfig.column, _ctx.columnStates); + }, + key: columnConfig.column + }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", { + class: "select", + type: _ctx.multiselect ? 'checkbox' : 'radio', + checked: !!_ctx.columnStates[columnConfig.column] + }, null, 8, _hoisted_4), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(columnConfig.translation), 1)])], 8, _hoisted_3); + }), 128)), _ctx.selectableRows.length ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("p", _hoisted_5, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_RecordsToPlot')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.selectableRows, function (rowConfig) { + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("p", { + class: "pickRow", + onClick: function onClick($event) { + return _ctx.optionSelected(rowConfig.matcher, _ctx.rowStates); + }, + key: rowConfig.matcher + }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", { + class: "select", + type: _ctx.multiselect ? 'checkbox' : 'radio', + checked: !!_ctx.rowStates[rowConfig.matcher] + }, null, 8, _hoisted_7), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(rowConfig.label), 1)])], 8, _hoisted_6); + }), 128))])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)], 34); +} +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue?vue&type=template&id=bd202f38 + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue?vue&type=script&lang=ts + + + +function getInitialOptionStates(allOptions, selectedOptions) { + var states = {}; + allOptions.forEach(function (columnConfig) { + var name = columnConfig.column || columnConfig.matcher; + states[name] = false; + }); + selectedOptions.forEach(function (column) { + states[column] = true; + }); + return states; +} + +function arrayEqual(lhs, rhs) { + if (lhs.length !== rhs.length) { + return false; + } + + return lhs.filter(function (element) { + return rhs.indexOf(element) === -1; + }).length === 0; +} + +function unselectOptions(optionStates) { + Object.keys(optionStates).forEach(function (optionName) { + optionStates[optionName] = false; + }); +} + +function getSelected(optionStates) { + return Object.keys(optionStates).filter(function (optionName) { + return !!optionStates[optionName]; + }); +} + +/* harmony default export */ var SeriesPickervue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({ + props: { + multiselect: Boolean, + selectableColumns: { + type: Array, + default: function _default() { + return []; + } + }, + selectableRows: { + type: Array, + default: function _default() { + return []; + } + }, + selectedColumns: { + type: Array, + default: function _default() { + return []; + } + }, + selectedRows: { + type: Array, + default: function _default() { + return []; + } + } + }, + data: function data() { + return { + isPopupVisible: false, + columnStates: getInitialOptionStates(this.selectableColumns, this.selectedColumns), + rowStates: getInitialOptionStates(this.selectableRows, this.selectedRows) + }; + }, + emits: ['select'], + created: function created() { + this.optionSelected = Object(external_CoreHome_["debounce"])(this.optionSelected, 0); + }, + methods: { + optionSelected: function optionSelected(optionValue, optionStates) { + if (!this.multiselect) { + unselectOptions(this.columnStates); + unselectOptions(this.rowStates); + } + + optionStates[optionValue] = !optionStates[optionValue]; + this.triggerOnSelectAndClose(); + }, + onLeavePopup: function onLeavePopup() { + this.isPopupVisible = false; + + if (this.optionsChanged()) { + this.triggerOnSelectAndClose(); + } + }, + triggerOnSelectAndClose: function triggerOnSelectAndClose() { + this.isPopupVisible = false; + this.$emit('select', { + columns: getSelected(this.columnStates), + rows: getSelected(this.rowStates) + }); + }, + optionsChanged: function optionsChanged() { + return !arrayEqual(getSelected(this.columnStates), this.selectedColumns) || !arrayEqual(getSelected(this.rowStates), this.selectedRows); + } + } +})); +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue?vue&type=script&lang=ts + +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue + + + +SeriesPickervue_type_script_lang_ts.render = SeriesPickervue_type_template_id_bd202f38_render + +/* harmony default export */ var SeriesPicker = (SeriesPickervue_type_script_lang_ts); +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.adapter.ts +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + +/* harmony default export */ var SeriesPicker_adapter = (Object(external_CoreHome_["createAngularJsAdapter"])({ + component: SeriesPicker, + scope: { + multiselect: { + angularJsBind: '<' + }, + selectableColumns: { + angularJsBind: '<' + }, + selectableRows: { + angularJsBind: '<' + }, + selectedColumns: { + angularJsBind: '<' + }, + selectedRows: { + angularJsBind: '<' + }, + onSelect: { + angularJsBind: '&', + vue: 'select' + } + }, + directiveName: 'piwikSeriesPicker', + restrict: 'E' +})); +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-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--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue?vue&type=template&id=2e2e889f + +var SingleMetricViewvue_type_template_id_2e2e889f_hoisted_1 = { + class: "metric-sparkline" +}; +var SingleMetricViewvue_type_template_id_2e2e889f_hoisted_2 = { + class: "metric-value" +}; +var SingleMetricViewvue_type_template_id_2e2e889f_hoisted_3 = ["title"]; +var SingleMetricViewvue_type_template_id_2e2e889f_hoisted_4 = ["title"]; +function SingleMetricViewvue_type_template_id_2e2e889f_render(_ctx, _cache, $props, $setup, $data, $options) { + var _component_Sparkline = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("Sparkline"); + + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", { + class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])(["singleMetricView", { + 'loading': _ctx.isLoading + }]), + ref: "root" + }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", SingleMetricViewvue_type_template_id_2e2e889f_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Sparkline, { + params: _ctx.sparklineParams + }, null, 8, ["params"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", SingleMetricViewvue_type_template_id_2e2e889f_hoisted_2, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", { + title: _ctx.metricDocumentation + }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("strong", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.metricValue), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(" " + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])((_ctx.metricTranslation || '').toLowerCase()), 1)], 8, SingleMetricViewvue_type_template_id_2e2e889f_hoisted_3), _ctx.pastValue !== null ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", { + key: 0, + class: "metricEvolution", + title: _ctx.translate('General_EvolutionSummaryGeneric', _ctx.metricValue, _ctx.currentPeriod, _ctx.pastValue, _ctx.pastPeriod, _ctx.metricChangePercent) + }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", { + class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])({ + 'positive-evolution': _ctx.metricValueUnformatted > _ctx.pastValueUnformatted, + 'negative-evolution': _ctx.metricValueUnformatted < _ctx.pastValueUnformatted + }) + }, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.metricChangePercent), 3)], 8, SingleMetricViewvue_type_template_id_2e2e889f_hoisted_4)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])], 2); +} +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue?vue&type=template&id=2e2e889f + +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue?vue&type=script&lang=ts +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } + +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } + +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } + +function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + + + + + +function getPastPeriodStr() { + var _Range$getLastNRange = external_CoreHome_["Range"].getLastNRange(external_CoreHome_["Matomo"].period, 2, external_CoreHome_["Matomo"].currentDateString), + startDate = _Range$getLastNRange.startDate; + + var dateRange = external_CoreHome_["Periods"].get(external_CoreHome_["Matomo"].period).parse(startDate).getDateRange(); + return "".concat(Object(external_CoreHome_["format"])(dateRange[0]), ",").concat(Object(external_CoreHome_["format"])(dateRange[1])); +} + +var _window = window, + $ = _window.$; +/* harmony default export */ var SingleMetricViewvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({ + props: { + metric: { + type: String, + required: true + }, + idGoal: [String, Number], + metricTranslations: { + type: Object, + required: true + }, + metricDocumentations: Object, + goals: { + type: Object, + required: true + }, + goalMetrics: Array + }, + components: { + Sparkline: external_CoreHome_["Sparkline"] + }, + setup: function setup(props) { + var root = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null); + var isLoading = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(false); + var responses = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(null); + var actualMetric = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(props.metric); + var actualIdGoal = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["ref"])(props.idGoal); + var selectedColumns = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + return [actualIdGoal.value ? "goal".concat(actualIdGoal.value, "_").concat(actualMetric.value) : actualMetric.value]; + }); + var metricValueUnformatted = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var _responses$value; + + if (!((_responses$value = responses.value) !== null && _responses$value !== void 0 && _responses$value[1])) { + return null; + } + + return responses.value[1][actualMetric.value]; + }); + var pastValueUnformatted = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var _responses$value2; + + if (!((_responses$value2 = responses.value) !== null && _responses$value2 !== void 0 && _responses$value2[2])) { + return null; + } + + return responses.value[2][actualMetric.value] || 0; + }); + var metricChangePercent = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + if (!metricValueUnformatted.value) { + return null; + } + + var currentValue = typeof metricValueUnformatted.value === 'string' ? parseInt(metricValueUnformatted.value, 10) : metricValueUnformatted.value; + var pastValue = typeof pastValueUnformatted.value === 'string' ? parseInt(pastValueUnformatted.value, 10) : pastValueUnformatted.value; + var evolution = external_CoreHome_["Matomo"].helper.calculateEvolution(currentValue, pastValue); + return "".concat((evolution * 100).toFixed(2), " %"); + }); + var pastValue = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var _responses$value3; + + if (!((_responses$value3 = responses.value) !== null && _responses$value3 !== void 0 && _responses$value3[3])) { + return null; + } + + var pastDataFormatted = responses.value[3]; + return pastDataFormatted[actualMetric.value] || 0; + }); + var metricValue = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var _responses$value4; + + if (!((_responses$value4 = responses.value) !== null && _responses$value4 !== void 0 && _responses$value4[0])) { + return null; + } + + var currentData = responses.value[0]; + return currentData[actualMetric.value] || 0; + }); + var metricTranslation = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var _props$metricTranslat; + + if (!((_props$metricTranslat = props.metricTranslations) !== null && _props$metricTranslat !== void 0 && _props$metricTranslat[actualMetric.value])) { + return ''; + } + + return props.metricTranslations[actualMetric.value]; + }); + var metricDocumentation = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var _props$metricDocument; + + if (!((_props$metricDocument = props.metricDocumentations) !== null && _props$metricDocument !== void 0 && _props$metricDocument[actualMetric.value])) { + return ''; + } + + return props.metricDocumentations[actualMetric.value]; + }); + var currentPeriod = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + if (external_CoreHome_["Matomo"].startDateString === external_CoreHome_["Matomo"].endDateString) { + return external_CoreHome_["Matomo"].endDateString; + } + + return "".concat(external_CoreHome_["Matomo"].startDateString, ", ").concat(external_CoreHome_["Matomo"].endDateString); + }); + + function isIdGoalSet() { + return actualIdGoal.value || actualIdGoal.value === 0; + } + + var sparklineParams = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var params = { + module: 'API', + action: 'get', + columns: actualMetric.value + }; + + if (isIdGoalSet()) { + params.idGoal = actualIdGoal.value; + params.module = 'Goals'; + } + + return params; + }); + var pastPeriod = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + if (external_CoreHome_["Matomo"].period === 'range') { + return undefined; + } + + return getPastPeriodStr(); + }); + var selectableColumns = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["computed"])(function () { + var result = []; + Object.keys(props.metricTranslations).forEach(function (column) { + result.push({ + column: column, + translation: props.metricTranslations[column] + }); + }); + Object.values(props.goals || {}).forEach(function (goal) { + props.goalMetrics.forEach(function (column) { + result.push({ + column: "goal".concat(goal.idgoal, "_").concat(column), + translation: "".concat(goal.name, " - ").concat(props.metricTranslations[column]) + }); + }); + }); + return result; + }); + + function setWidgetTitle() { + var title = metricTranslation.value; + + if (isIdGoalSet()) { + var _props$goals$actualId; + + var goalName = ((_props$goals$actualId = props.goals[actualIdGoal.value]) === null || _props$goals$actualId === void 0 ? void 0 : _props$goals$actualId.name) || Object(external_CoreHome_["translate"])('General_Unknown'); + title = "".concat(goalName, " - ").concat(title); + } + + $(root.value).closest('div.widget').find('.widgetTop > .widgetName > span').text(title); + } + + function getLastPeriodDate() { + var range = external_CoreHome_["Range"].getLastNRange(external_CoreHome_["Matomo"].period, 2, external_CoreHome_["Matomo"].currentDateString); + return Object(external_CoreHome_["format"])(range.startDate); + } + + function fetchData() { + isLoading.value = true; + var promises = []; + var apiModule = 'API'; + var apiAction = 'get'; + var extraParams = {}; + + if (isIdGoalSet()) { + // the conversion rate added by the AddColumnsProcessedMetrics filter conflicts w/ + // the goals one, so don't run it + extraParams.idGoal = actualIdGoal.value; + extraParams.filter_add_columns_when_show_all_columns = 0; + apiModule = 'Goals'; + apiAction = 'get'; + } + + var method = "".concat(apiModule, ".").concat(apiAction); // first request for formatted data + + promises.push(external_CoreHome_["AjaxHelper"].fetch(Object.assign({ + method: method, + format_metrics: 'all' + }, extraParams))); + + if (external_CoreHome_["Matomo"].period !== 'range') { + // second request for unformatted data so we can calculate evolution + promises.push(external_CoreHome_["AjaxHelper"].fetch(Object.assign({ + method: method, + format_metrics: '0' + }, extraParams))); // third request for past data (unformatted) + + promises.push(external_CoreHome_["AjaxHelper"].fetch(Object.assign({ + method: method, + date: getLastPeriodDate(), + format_metrics: '0' + }, extraParams))); // fourth request for past data (formatted for tooltip display) + + promises.push(external_CoreHome_["AjaxHelper"].fetch(Object.assign({ + method: method, + date: getLastPeriodDate(), + format_metrics: 'all' + }, extraParams))); + } + + return Promise.all(promises).then(function (r) { + responses.value = r; + isLoading.value = false; + }); + } + + function onMetricChanged(newMetric) { + actualMetric.value = newMetric; + fetchData().then(setWidgetTitle); // notify widget of parameter change so it is replaced + + $(root.value).closest('[widgetId]').trigger('setParameters', { + column: actualMetric.value, + idGoal: actualIdGoal.value + }); + } + + function setMetric(newColumn) { + var idGoal = undefined; + var actualColumn = newColumn; + var m = newColumn.match(/^goal([0-9]+)_(.*)/); + + if (m) { + idGoal = +m[1]; + + var _m = _slicedToArray(m, 3); + + actualColumn = _m[2]; + } + + if (actualMetric.value !== actualColumn || idGoal !== actualIdGoal.value) { + actualMetric.value = actualColumn; + actualIdGoal.value = idGoal; + onMetricChanged(actualColumn); + } + } + + function createSeriesPicker() { + var element = $(root.value); + var $widgetName = element.closest('div.widget').find('.widgetTop > .widgetName'); + var $seriesPickerElem = $('<div class="single-metric-view-picker"><div></div></div>'); + var app = Object(external_CoreHome_["createVueApp"])({ + render: function render() { + return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(SeriesPicker, { + multiselect: false, + selectableColumns: selectableColumns.value, + selectableRows: [], + selectedColumns: selectedColumns.value, + selectedRows: [], + onSelect: function onSelect(_ref) { + var columns = _ref.columns; + setMetric(columns[0]); + } + }); + } + }); + $widgetName.append($seriesPickerElem); + app.mount($seriesPickerElem.children()[0]); + return app; + } + + var seriesPickerApp; + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["onMounted"])(function () { + seriesPickerApp = createSeriesPicker(); + }); + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["onBeforeUnmount"])(function () { + $(root.value).closest('.widgetContent').off('widget:destroy').off('widget:reload'); + $(root.value).closest('div.widget').find('.single-metric-view-picker').remove(); + seriesPickerApp.unmount(); + }); + Object(external_commonjs_vue_commonjs2_vue_root_Vue_["watch"])(function () { + return props.metric; + }, function () { + onMetricChanged(props.metric); + }); + onMetricChanged(props.metric); + return { + root: root, + metricValue: metricValue, + isLoading: isLoading, + selectedColumns: selectedColumns, + responses: responses, + metricValueUnformatted: metricValueUnformatted, + pastValueUnformatted: pastValueUnformatted, + metricChangePercent: metricChangePercent, + pastValue: pastValue, + metricTranslation: metricTranslation, + metricDocumentation: metricDocumentation, + sparklineParams: sparklineParams, + pastPeriod: pastPeriod, + selectableColumns: selectableColumns, + currentPeriod: currentPeriod + }; + } +})); +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue?vue&type=script&lang=ts + +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue + + + +SingleMetricViewvue_type_script_lang_ts.render = SingleMetricViewvue_type_template_id_2e2e889f_render + +/* harmony default export */ var SingleMetricView = (SingleMetricViewvue_type_script_lang_ts); +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.adapter.ts +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + +/* harmony default export */ var SingleMetricView_adapter = (Object(external_CoreHome_["createAngularJsAdapter"])({ + component: SingleMetricView, + scope: { + metric: { + angularJsBind: '<' + }, + idGoal: { + angularJsBind: '<' + }, + metricTranslations: { + angularJsBind: '<' + }, + metricDocumentations: { + angularJsBind: '<' + }, + goals: { + angularJsBind: '<' + }, + goalMetrics: { + angularJsBind: '<' + } + }, + directiveName: 'piwikSingleMetricView', + restrict: 'E', + postCreate: function postCreate(vm, scope, element) { + element.closest('.widgetContent').on('widget:destroy', function () { + scope.$parent.$destroy(); + }).on('widget:reload', function () { + scope.$parent.$destroy(); + }); + } +})); +// CONCATENATED MODULE: ./plugins/CoreVisualizations/vue/src/index.ts +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + + + +// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib-no-default.js + + + + +/***/ }) + +/******/ }); +}); +//# sourceMappingURL=CoreVisualizations.umd.js.map
\ No newline at end of file diff --git a/plugins/CoreVisualizations/vue/dist/CoreVisualizations.umd.min.js b/plugins/CoreVisualizations/vue/dist/CoreVisualizations.umd.min.js new file mode 100644 index 0000000000..f13b9f8384 --- /dev/null +++ b/plugins/CoreVisualizations/vue/dist/CoreVisualizations.umd.min.js @@ -0,0 +1,14 @@ +(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["CoreVisualizations"]=t(require("CoreHome"),require("vue")):e["CoreVisualizations"]=t(e["CoreHome"],e["Vue"])})("undefined"!==typeof self?self:this,(function(e,t){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="plugins/CoreVisualizations/vue/dist/",n(n.s="fae3")}({"19dc":function(t,n){t.exports=e},"8bbf":function(e,n){e.exports=t},fae3:function(e,t,n){"use strict";if(n.r(t),n.d(t,"SeriesPicker",(function(){return h})),n.d(t,"SingleMetricView",(function(){return T})),"undefined"!==typeof window){var r=window.document.currentScript,o=r&&r.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);o&&(n.p=o[1])}var c=n("19dc"),a=n("8bbf"),l={key:0,class:"jqplot-seriespicker-popover"},i={class:"headline"},u=["onClick"],s=["type","checked"],d={key:0,class:"headline recordsToPlot"},m=["onClick"],p=["type","checked"];function f(e,t,n,r,o,c){return Object(a["openBlock"])(),Object(a["createElementBlock"])("div",{class:Object(a["normalizeClass"])(["jqplot-seriespicker",{open:e.isPopupVisible}]),onMouseenter:t[1]||(t[1]=function(t){return e.isPopupVisible=!0}),onMouseleave:t[2]||(t[2]=function(t){return e.onLeavePopup()})},[Object(a["createElementVNode"])("a",{href:"#",onClick:t[0]||(t[0]=Object(a["withModifiers"])((function(){}),["prevent","stop"]))}," + "),e.isPopupVisible?(Object(a["openBlock"])(),Object(a["createElementBlock"])("div",l,[Object(a["createElementVNode"])("p",i,Object(a["toDisplayString"])(e.translate(e.multiselect?"General_MetricsToPlot":"General_MetricToPlot")),1),(Object(a["openBlock"])(!0),Object(a["createElementBlock"])(a["Fragment"],null,Object(a["renderList"])(e.selectableColumns,(function(t){return Object(a["openBlock"])(),Object(a["createElementBlock"])("p",{class:"pickColumn",onClick:function(n){return e.optionSelected(t.column,e.columnStates)},key:t.column},[Object(a["createElementVNode"])("label",null,[Object(a["createElementVNode"])("input",{class:"select",type:e.multiselect?"checkbox":"radio",checked:!!e.columnStates[t.column]},null,8,s),Object(a["createElementVNode"])("span",null,Object(a["toDisplayString"])(t.translation),1)])],8,u)})),128)),e.selectableRows.length?(Object(a["openBlock"])(),Object(a["createElementBlock"])("p",d,Object(a["toDisplayString"])(e.translate("General_RecordsToPlot")),1)):Object(a["createCommentVNode"])("",!0),(Object(a["openBlock"])(!0),Object(a["createElementBlock"])(a["Fragment"],null,Object(a["renderList"])(e.selectableRows,(function(t){return Object(a["openBlock"])(),Object(a["createElementBlock"])("p",{class:"pickRow",onClick:function(n){return e.optionSelected(t.matcher,e.rowStates)},key:t.matcher},[Object(a["createElementVNode"])("label",null,[Object(a["createElementVNode"])("input",{class:"select",type:e.multiselect?"checkbox":"radio",checked:!!e.rowStates[t.matcher]},null,8,p),Object(a["createElementVNode"])("span",null,Object(a["toDisplayString"])(t.label),1)])],8,m)})),128))])):Object(a["createCommentVNode"])("",!0)],34)}function b(e,t){var n={};return e.forEach((function(e){var t=e.column||e.matcher;n[t]=!1})),t.forEach((function(e){n[e]=!0})),n}function v(e,t){return e.length===t.length&&0===e.filter((function(e){return-1===t.indexOf(e)})).length}function g(e){Object.keys(e).forEach((function(t){e[t]=!1}))}function j(e){return Object.keys(e).filter((function(t){return!!e[t]}))}var O=Object(a["defineComponent"])({props:{multiselect:Boolean,selectableColumns:{type:Array,default:function(){return[]}},selectableRows:{type:Array,default:function(){return[]}},selectedColumns:{type:Array,default:function(){return[]}},selectedRows:{type:Array,default:function(){return[]}}},data:function(){return{isPopupVisible:!1,columnStates:b(this.selectableColumns,this.selectedColumns),rowStates:b(this.selectableRows,this.selectedRows)}},emits:["select"],created:function(){this.optionSelected=Object(c["debounce"])(this.optionSelected,0)},methods:{optionSelected:function(e,t){this.multiselect||(g(this.columnStates),g(this.rowStates)),t[e]=!t[e],this.triggerOnSelectAndClose()},onLeavePopup:function(){this.isPopupVisible=!1,this.optionsChanged()&&this.triggerOnSelectAndClose()},triggerOnSelectAndClose:function(){this.isPopupVisible=!1,this.$emit("select",{columns:j(this.columnStates),rows:j(this.rowStates)})},optionsChanged:function(){return!v(j(this.columnStates),this.selectedColumns)||!v(j(this.rowStates),this.selectedRows)}}});O.render=f;var h=O,y=(Object(c["createAngularJsAdapter"])({component:h,scope:{multiselect:{angularJsBind:"<"},selectableColumns:{angularJsBind:"<"},selectableRows:{angularJsBind:"<"},selectedColumns:{angularJsBind:"<"},selectedRows:{angularJsBind:"<"},onSelect:{angularJsBind:"&",vue:"select"}},directiveName:"piwikSeriesPicker",restrict:"E"}),{class:"metric-sparkline"}),w={class:"metric-value"},S=["title"],k=["title"]; +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */function C(e,t,n,r,o,c){var l=Object(a["resolveComponent"])("Sparkline");return Object(a["openBlock"])(),Object(a["createElementBlock"])("div",{class:Object(a["normalizeClass"])(["singleMetricView",{loading:e.isLoading}]),ref:"root"},[Object(a["createElementVNode"])("div",y,[Object(a["createVNode"])(l,{params:e.sparklineParams},null,8,["params"])]),Object(a["createElementVNode"])("div",w,[Object(a["createElementVNode"])("span",{title:e.metricDocumentation},[Object(a["createElementVNode"])("strong",null,Object(a["toDisplayString"])(e.metricValue),1),Object(a["createTextVNode"])(" "+Object(a["toDisplayString"])((e.metricTranslation||"").toLowerCase()),1)],8,S),null!==e.pastValue?(Object(a["openBlock"])(),Object(a["createElementBlock"])("span",{key:0,class:"metricEvolution",title:e.translate("General_EvolutionSummaryGeneric",e.metricValue,e.currentPeriod,e.pastValue,e.pastPeriod,e.metricChangePercent)},[Object(a["createElementVNode"])("span",{class:Object(a["normalizeClass"])({"positive-evolution":e.metricValueUnformatted>e.pastValueUnformatted,"negative-evolution":e.metricValueUnformatted<e.pastValueUnformatted})},Object(a["toDisplayString"])(e.metricChangePercent),3)],8,k)):Object(a["createCommentVNode"])("",!0)])],2)}function V(e,t){return N(e)||M(e,t)||P(e,t)||E()}function E(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function P(e,t){if(e){if("string"===typeof e)return B(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?B(e,t):void 0}}function B(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function M(e,t){var n=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,c=[],a=!0,l=!1;try{for(n=n.call(e);!(a=(r=n.next()).done);a=!0)if(c.push(r.value),t&&c.length===t)break}catch(i){l=!0,o=i}finally{try{a||null==n["return"]||n["return"]()}finally{if(l)throw o}}return c}}function N(e){if(Array.isArray(e))return e}function A(){var e=c["Range"].getLastNRange(c["Matomo"].period,2,c["Matomo"].currentDateString),t=e.startDate,n=c["Periods"].get(c["Matomo"].period).parse(t).getDateRange();return"".concat(Object(c["format"])(n[0]),",").concat(Object(c["format"])(n[1]))}var _=window,D=_.$,x=Object(a["defineComponent"])({props:{metric:{type:String,required:!0},idGoal:[String,Number],metricTranslations:{type:Object,required:!0},metricDocumentations:Object,goals:{type:Object,required:!0},goalMetrics:Array},components:{Sparkline:c["Sparkline"]},setup:function(e){var t=Object(a["ref"])(null),n=Object(a["ref"])(!1),r=Object(a["ref"])(null),o=Object(a["ref"])(e.metric),l=Object(a["ref"])(e.idGoal),i=Object(a["computed"])((function(){return[l.value?"goal".concat(l.value,"_").concat(o.value):o.value]})),u=Object(a["computed"])((function(){var e;return null!==(e=r.value)&&void 0!==e&&e[1]?r.value[1][o.value]:null})),s=Object(a["computed"])((function(){var e;return null!==(e=r.value)&&void 0!==e&&e[2]?r.value[2][o.value]||0:null})),d=Object(a["computed"])((function(){if(!u.value)return null;var e="string"===typeof u.value?parseInt(u.value,10):u.value,t="string"===typeof s.value?parseInt(s.value,10):s.value,n=c["Matomo"].helper.calculateEvolution(e,t);return"".concat((100*n).toFixed(2)," %")})),m=Object(a["computed"])((function(){var e;if(null===(e=r.value)||void 0===e||!e[3])return null;var t=r.value[3];return t[o.value]||0})),p=Object(a["computed"])((function(){var e;if(null===(e=r.value)||void 0===e||!e[0])return null;var t=r.value[0];return t[o.value]||0})),f=Object(a["computed"])((function(){var t;return null!==(t=e.metricTranslations)&&void 0!==t&&t[o.value]?e.metricTranslations[o.value]:""})),b=Object(a["computed"])((function(){var t;return null!==(t=e.metricDocumentations)&&void 0!==t&&t[o.value]?e.metricDocumentations[o.value]:""})),v=Object(a["computed"])((function(){return c["Matomo"].startDateString===c["Matomo"].endDateString?c["Matomo"].endDateString:"".concat(c["Matomo"].startDateString,", ").concat(c["Matomo"].endDateString)}));function g(){return l.value||0===l.value}var j,O=Object(a["computed"])((function(){var e={module:"API",action:"get",columns:o.value};return g()&&(e.idGoal=l.value,e.module="Goals"),e})),y=Object(a["computed"])((function(){if("range"!==c["Matomo"].period)return A()})),w=Object(a["computed"])((function(){var t=[];return Object.keys(e.metricTranslations).forEach((function(n){t.push({column:n,translation:e.metricTranslations[n]})})),Object.values(e.goals||{}).forEach((function(n){e.goalMetrics.forEach((function(r){t.push({column:"goal".concat(n.idgoal,"_").concat(r),translation:"".concat(n.name," - ").concat(e.metricTranslations[r])})}))})),t}));function S(){var n=f.value;if(g()){var r,o=(null===(r=e.goals[l.value])||void 0===r?void 0:r.name)||Object(c["translate"])("General_Unknown");n="".concat(o," - ").concat(n)}D(t.value).closest("div.widget").find(".widgetTop > .widgetName > span").text(n)}function k(){var e=c["Range"].getLastNRange(c["Matomo"].period,2,c["Matomo"].currentDateString);return Object(c["format"])(e.startDate)}function C(){n.value=!0;var e=[],t="API",o="get",a={};g()&&(a.idGoal=l.value,a.filter_add_columns_when_show_all_columns=0,t="Goals",o="get");var i="".concat(t,".").concat(o);return e.push(c["AjaxHelper"].fetch(Object.assign({method:i,format_metrics:"all"},a))),"range"!==c["Matomo"].period&&(e.push(c["AjaxHelper"].fetch(Object.assign({method:i,format_metrics:"0"},a))),e.push(c["AjaxHelper"].fetch(Object.assign({method:i,date:k(),format_metrics:"0"},a))),e.push(c["AjaxHelper"].fetch(Object.assign({method:i,date:k(),format_metrics:"all"},a)))),Promise.all(e).then((function(e){r.value=e,n.value=!1}))}function E(e){o.value=e,C().then(S),D(t.value).closest("[widgetId]").trigger("setParameters",{column:o.value,idGoal:l.value})}function P(e){var t=void 0,n=e,r=e.match(/^goal([0-9]+)_(.*)/);if(r){t=+r[1];var c=V(r,3);n=c[2]}o.value===n&&t===l.value||(o.value=n,l.value=t,E(n))}function B(){var e=D(t.value),n=e.closest("div.widget").find(".widgetTop > .widgetName"),r=D('<div class="single-metric-view-picker"><div></div></div>'),o=Object(c["createVueApp"])({render:function(){return Object(a["createVNode"])(h,{multiselect:!1,selectableColumns:w.value,selectableRows:[],selectedColumns:i.value,selectedRows:[],onSelect:function(e){var t=e.columns;P(t[0])}})}});return n.append(r),o.mount(r.children()[0]),o}return Object(a["onMounted"])((function(){j=B()})),Object(a["onBeforeUnmount"])((function(){D(t.value).closest(".widgetContent").off("widget:destroy").off("widget:reload"),D(t.value).closest("div.widget").find(".single-metric-view-picker").remove(),j.unmount()})),Object(a["watch"])((function(){return e.metric}),(function(){E(e.metric)})),E(e.metric),{root:t,metricValue:p,isLoading:n,selectedColumns:i,responses:r,metricValueUnformatted:u,pastValueUnformatted:s,metricChangePercent:d,pastValue:m,metricTranslation:f,metricDocumentation:b,sparklineParams:O,pastPeriod:y,selectableColumns:w,currentPeriod:v}}});x.render=C;var T=x; +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */Object(c["createAngularJsAdapter"])({component:T,scope:{metric:{angularJsBind:"<"},idGoal:{angularJsBind:"<"},metricTranslations:{angularJsBind:"<"},metricDocumentations:{angularJsBind:"<"},goals:{angularJsBind:"<"},goalMetrics:{angularJsBind:"<"}},directiveName:"piwikSingleMetricView",restrict:"E",postCreate:function(e,t,n){n.closest(".widgetContent").on("widget:destroy",(function(){t.$parent.$destroy()})).on("widget:reload",(function(){t.$parent.$destroy()}))}})}})})); +//# sourceMappingURL=CoreVisualizations.umd.min.js.map
\ No newline at end of file diff --git a/plugins/CoreVisualizations/vue/dist/umd.metadata.json b/plugins/CoreVisualizations/vue/dist/umd.metadata.json new file mode 100644 index 0000000000..9ecfcc0456 --- /dev/null +++ b/plugins/CoreVisualizations/vue/dist/umd.metadata.json @@ -0,0 +1,5 @@ +{ + "dependsOn": [ + "CoreHome" + ] +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.adapter.ts b/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.adapter.ts new file mode 100644 index 0000000000..31a253be25 --- /dev/null +++ b/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.adapter.ts @@ -0,0 +1,36 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import { createAngularJsAdapter } from 'CoreHome'; +import SeriesPicker from './SeriesPicker.vue'; + +export default createAngularJsAdapter({ + component: SeriesPicker, + scope: { + multiselect: { + angularJsBind: '<', + }, + selectableColumns: { + angularJsBind: '<', + }, + selectableRows: { + angularJsBind: '<', + }, + selectedColumns: { + angularJsBind: '<', + }, + selectedRows: { + angularJsBind: '<', + }, + onSelect: { + angularJsBind: '&', + vue: 'select', + }, + }, + directiveName: 'piwikSeriesPicker', + restrict: 'E', +}); diff --git a/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.less b/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.less new file mode 100644 index 0000000000..656c602ce7 --- /dev/null +++ b/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.less @@ -0,0 +1,30 @@ +piwik-series-picker { + display: inline-block; +} + +.jqplot-seriespicker { + display: inline-block; + + &:not(.open) { + opacity: .55; + } + + &.open { // while open, make sure we're above other series picker icons + z-index: 1000; + } + + > a { + display: inline-block; + opacity: 0; + position: absolute; + } + + position: relative; +} + +.jqplot-seriespicker-popover { + position: absolute; + + top: -3px; + left: -4px; +} diff --git a/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue b/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue new file mode 100644 index 0000000000..4c4e433a85 --- /dev/null +++ b/plugins/CoreVisualizations/vue/src/SeriesPicker/SeriesPicker.vue @@ -0,0 +1,192 @@ +<!-- + Matomo - free/libre analytics platform + @link https://matomo.org + @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later +--> + +<template> + <div + class="jqplot-seriespicker" + @mouseenter="isPopupVisible = true" + @mouseleave="onLeavePopup()" + :class="{open: isPopupVisible}" + > + <a + href="#" + @click.prevent.stop + > + + + </a> + <div + class="jqplot-seriespicker-popover" + v-if="isPopupVisible" + > + <p class="headline"> + {{ translate(multiselect ? 'General_MetricsToPlot' : 'General_MetricToPlot') }}</p> + <p + class="pickColumn" + @click="optionSelected(columnConfig.column, columnStates)" + v-for="columnConfig in selectableColumns" + :key="columnConfig.column" + > + <label> + <input + class="select" + :type="multiselect ? 'checkbox' : 'radio'" + :checked="!!columnStates[columnConfig.column]" + /> + <span>{{ columnConfig.translation }}</span> + </label> + </p> + <p + class="headline recordsToPlot" + v-if="selectableRows.length" + > + {{ translate('General_RecordsToPlot') }} + </p> + <p + class="pickRow" + @click="optionSelected(rowConfig.matcher, rowStates)" + v-for="rowConfig in selectableRows" + :key="rowConfig.matcher" + > + <label> + <input + class="select" + :type="multiselect ? 'checkbox' : 'radio'" + :checked="!!rowStates[rowConfig.matcher]" + /> + <span>{{ rowConfig.label }}</span> + </label> + </p> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { debounce } from 'CoreHome'; + +interface SelectableColumnInfo { + column: string; + translation: string; +} + +interface SelectableRowInfo { + matcher: string; + label: string; +} + +interface SeriesPickerState { + isPopupVisible: boolean; + columnStates: Record<string, boolean>; + rowStates: Record<string, boolean>; +} + +function getInitialOptionStates( + allOptions: (SelectableColumnInfo | SelectableRowInfo)[], + selectedOptions: string[], +) { + const states: Record<string, boolean> = {}; + allOptions.forEach((columnConfig) => { + const name = (columnConfig as SelectableColumnInfo).column + || (columnConfig as SelectableRowInfo).matcher; + states[name] = false; + }); + selectedOptions.forEach((column) => { + states[column] = true; + }); + return states; +} + +function arrayEqual<T>(lhs: T[], rhs: T[]) { + if (lhs.length !== rhs.length) { + return false; + } + + return lhs.filter((element) => rhs.indexOf(element) === -1).length === 0; +} + +function unselectOptions(optionStates: Record<string, boolean>) { + Object.keys(optionStates).forEach((optionName) => { + optionStates[optionName] = false; + }); +} + +function getSelected(optionStates: Record<string, boolean>) { + return Object.keys(optionStates).filter((optionName) => !!optionStates[optionName]); +} + +export default defineComponent({ + props: { + multiselect: Boolean, + selectableColumns: { + type: Array, + default: () => [], + }, + selectableRows: { + type: Array, + default: () => [], + }, + selectedColumns: { + type: Array, + default: () => [], + }, + selectedRows: { + type: Array, + default: () => [], + }, + }, + data(): SeriesPickerState { + return { + isPopupVisible: false, + columnStates: getInitialOptionStates( + this.selectableColumns as SelectableColumnInfo[], + this.selectedColumns as string[], + ), + rowStates: getInitialOptionStates( + this.selectableRows as SelectableRowInfo[], + this.selectedRows as string[], + ), + }; + }, + emits: ['select'], + created() { + this.optionSelected = debounce(this.optionSelected, 0); + }, + methods: { + optionSelected(optionValue: string, optionStates: Record<string, boolean>) { + if (!this.multiselect) { + unselectOptions(this.columnStates); + unselectOptions(this.rowStates); + } + + optionStates[optionValue] = !optionStates[optionValue]; + this.triggerOnSelectAndClose(); + }, + onLeavePopup() { + this.isPopupVisible = false; + + if (this.optionsChanged()) { + this.triggerOnSelectAndClose(); + } + }, + triggerOnSelectAndClose() { + this.isPopupVisible = false; + this.$emit('select', { + columns: getSelected(this.columnStates), + rows: getSelected(this.rowStates), + }); + }, + optionsChanged() { + return !arrayEqual( + getSelected(this.columnStates), + this.selectedColumns, + ) || !arrayEqual( + getSelected(this.rowStates), + this.selectedRows, + ); + }, + }, +}); +</script> diff --git a/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.adapter.ts b/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.adapter.ts new file mode 100644 index 0000000000..7091b9bb66 --- /dev/null +++ b/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.adapter.ts @@ -0,0 +1,42 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import { createAngularJsAdapter } from 'CoreHome'; +import SingleMetricView from './SingleMetricView.vue'; + +export default createAngularJsAdapter({ + component: SingleMetricView, + scope: { + metric: { + angularJsBind: '<', + }, + idGoal: { + angularJsBind: '<', + }, + metricTranslations: { + angularJsBind: '<', + }, + metricDocumentations: { + angularJsBind: '<', + }, + goals: { + angularJsBind: '<', + }, + goalMetrics: { + angularJsBind: '<', + }, + }, + directiveName: 'piwikSingleMetricView', + restrict: 'E', + postCreate(vm, scope, element) { + element.closest('.widgetContent').on('widget:destroy', () => { + scope.$parent.$destroy(); + }).on('widget:reload', () => { + scope.$parent.$destroy(); + }); + }, +}); diff --git a/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.less b/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.less index f091b530e2..49d72536f2 100644 --- a/plugins/CoreVisualizations/angularjs/single-metric-view/single-metric-view.component.less +++ b/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.less @@ -6,6 +6,10 @@ opacity: 0.5; } + span, .metric-sparkline, .positive-evolution::before { + margin-right: 3.5px; + } + .metric-value { display: inline-block; font-size: 14px; @@ -58,4 +62,5 @@ .single-metric-view-picker { margin-left: 6px; + display: inline-block; }
\ No newline at end of file diff --git a/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue b/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue new file mode 100644 index 0000000000..a07c584673 --- /dev/null +++ b/plugins/CoreVisualizations/vue/src/SingleMetricView/SingleMetricView.vue @@ -0,0 +1,410 @@ +<!-- + Matomo - free/libre analytics platform + @link https://matomo.org + @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later +--> + +<template> + <div + class="singleMetricView" + :class="{'loading': isLoading}" + ref="root" + > + <div class="metric-sparkline"> + <Sparkline :params="sparklineParams"> + </Sparkline> + </div> + <div class="metric-value"> + <span :title="metricDocumentation"> + <strong>{{ metricValue }}</strong> {{ (metricTranslation || '').toLowerCase() }} + </span> + <span + class="metricEvolution" + v-if="pastValue !== null" + :title="translate( + 'General_EvolutionSummaryGeneric', metricValue, currentPeriod, pastValue, + pastPeriod, metricChangePercent)" + > + <span + :class="{ + 'positive-evolution': metricValueUnformatted > pastValueUnformatted, + 'negative-evolution': metricValueUnformatted < pastValueUnformatted, + }" + > + {{ metricChangePercent }} + </span> + </span> + </div> + </div> +</template> + +<script lang="ts"> +import { + computed, + createVNode, + defineComponent, + onBeforeUnmount, + onMounted, + ref, + watch, +} from 'vue'; +import { + Matomo, + AjaxHelper, + Sparkline, + Range, + Periods, + format, + createVueApp, translate, +} from 'CoreHome'; +import SeriesPicker from '../SeriesPicker/SeriesPicker.vue'; + +interface SelectableColumnInfo { + column: string; + translation: string; +} + +type MetricValues = Record<string, number|string>; + +interface Goal { + idgoal: string|number; + name: string; +} + +function getPastPeriodStr(): string { + const { startDate } = Range.getLastNRange(Matomo.period!, 2, Matomo.currentDateString!); + const dateRange = Periods.get(Matomo.period!).parse(startDate).getDateRange(); + return `${format(dateRange[0])},${format(dateRange[1])}`; +} + +const { $ } = window; + +export default defineComponent({ + props: { + metric: { + type: String, + required: true, + }, + idGoal: [String, Number], + metricTranslations: { + type: Object, + required: true, + }, + metricDocumentations: Object, + goals: { + type: Object, + required: true, + }, + goalMetrics: Array, + }, + components: { + Sparkline, + }, + setup(props) { + const root = ref<HTMLElement|null>(null); + + const isLoading = ref<boolean>(false); + const responses = ref<null|MetricValues[]>(null); + const actualMetric = ref<string>(props.metric); + const actualIdGoal = ref<string|number|undefined>(props.idGoal); + + const selectedColumns = computed(() => [ + actualIdGoal.value ? `goal${actualIdGoal.value}_${actualMetric.value}` : actualMetric.value, + ]); + + const metricValueUnformatted = computed(() => { + if (!responses.value?.[1]) { + return null; + } + + return responses.value[1][actualMetric.value]; + }); + + const pastValueUnformatted = computed(() => { + if (!responses.value?.[2]) { + return null; + } + + return responses.value[2][actualMetric.value] || 0; + }); + + const metricChangePercent = computed(() => { + if (!metricValueUnformatted.value) { + return null; + } + + const currentValue: number = typeof metricValueUnformatted.value === 'string' + ? parseInt(metricValueUnformatted.value, 10) + : metricValueUnformatted.value as number; + + const pastValue: number = typeof pastValueUnformatted.value === 'string' + ? parseInt(pastValueUnformatted.value, 10) + : pastValueUnformatted.value as number; + + const evolution = Matomo.helper.calculateEvolution(currentValue, pastValue); + + return `${(evolution * 100).toFixed(2)} %`; + }); + + const pastValue = computed(() => { + if (!responses.value?.[3]) { + return null; + } + + const pastDataFormatted = responses.value[3]; + return pastDataFormatted[actualMetric.value] || 0; + }); + + const metricValue = computed(() => { + if (!responses.value?.[0]) { + return null; + } + + const currentData = responses.value[0]; + return currentData[actualMetric.value] || 0; + }); + + const metricTranslation = computed(() => { + if (!props.metricTranslations?.[actualMetric.value]) { + return ''; + } + + return props.metricTranslations[actualMetric.value]; + }); + + const metricDocumentation = computed(() => { + if (!props.metricDocumentations?.[actualMetric.value]) { + return ''; + } + + return props.metricDocumentations[actualMetric.value]; + }); + + const currentPeriod = computed(() => { + if (Matomo.startDateString === Matomo.endDateString) { + return Matomo.endDateString; + } + return `${Matomo.startDateString}, ${Matomo.endDateString}`; + }); + + function isIdGoalSet() { + return actualIdGoal.value || actualIdGoal.value === 0; + } + + const sparklineParams = computed<QueryParameters>(() => { + const params: QueryParameters = { + module: 'API', + action: 'get', + columns: actualMetric.value, + }; + + if (isIdGoalSet()) { + params.idGoal = actualIdGoal.value; + params.module = 'Goals'; + } + + return params; + }); + + const pastPeriod = computed(() => { + if (Matomo.period === 'range') { + return undefined; + } + + return getPastPeriodStr(); + }); + + const selectableColumns = computed(() => { + const result: SelectableColumnInfo[] = []; + + Object.keys(props.metricTranslations).forEach((column) => { + result.push({ + column, + translation: props.metricTranslations[column], + }); + }); + + Object.values((props.goals || {}) as Record<string, Goal>).forEach((goal) => { + (props.goalMetrics as string[]).forEach((column) => { + result.push({ + column: `goal${goal.idgoal}_${column}`, + translation: `${goal.name} - ${props.metricTranslations[column]}`, + }); + }); + }); + + return result; + }); + + function setWidgetTitle() { + let title = metricTranslation.value; + + if (isIdGoalSet()) { + const goalName = props.goals[actualIdGoal.value!]?.name || translate('General_Unknown'); + title = `${goalName} - ${title}`; + } + + $(root.value as HTMLElement) + .closest('div.widget') + .find('.widgetTop > .widgetName > span') + .text(title); + } + + function getLastPeriodDate(): string { + const range = Range.getLastNRange(Matomo.period!, 2, Matomo.currentDateString!); + return format(range.startDate); + } + + function fetchData() { + isLoading.value = true; + + const promises = []; + let apiModule = 'API'; + let apiAction = 'get'; + const extraParams: QueryParameters = {}; + + if (isIdGoalSet()) { + // the conversion rate added by the AddColumnsProcessedMetrics filter conflicts w/ + // the goals one, so don't run it + extraParams.idGoal = actualIdGoal.value; + + extraParams.filter_add_columns_when_show_all_columns = 0; + apiModule = 'Goals'; + apiAction = 'get'; + } + + const method = `${apiModule}.${apiAction}`; + + // first request for formatted data + promises.push(AjaxHelper.fetch({ + method, + format_metrics: 'all', + ...extraParams, + })); + + if (Matomo.period !== 'range') { + // second request for unformatted data so we can calculate evolution + promises.push(AjaxHelper.fetch({ + method, + format_metrics: '0', + ...extraParams, + })); + + // third request for past data (unformatted) + promises.push(AjaxHelper.fetch({ + method, + date: getLastPeriodDate(), + format_metrics: '0', + ...extraParams, + })); + + // fourth request for past data (formatted for tooltip display) + promises.push(AjaxHelper.fetch({ + method, + date: getLastPeriodDate(), + format_metrics: 'all', + ...extraParams, + })); + } + + return Promise.all(promises).then((r) => { + responses.value = r; + isLoading.value = false; + }); + } + + function onMetricChanged(newMetric: string) { + actualMetric.value = newMetric; + + fetchData().then(setWidgetTitle); // notify widget of parameter change so it is replaced + + $(root.value as HTMLElement).closest('[widgetId]').trigger('setParameters', { + column: actualMetric.value, + idGoal: actualIdGoal.value, + }); + } + + function setMetric(newColumn: string) { + let idGoal: number|undefined = undefined; + let actualColumn: string = newColumn; + + const m = newColumn.match(/^goal([0-9]+)_(.*)/); + if (m) { + idGoal = +m[1]; + [, , actualColumn] = m; + } + + if (actualMetric.value !== actualColumn || idGoal !== actualIdGoal.value) { + actualMetric.value = actualColumn; + actualIdGoal.value = idGoal; + onMetricChanged(actualColumn); + } + } + + function createSeriesPicker() { + const element = $(root.value as HTMLElement); + const $widgetName = element.closest('div.widget').find('.widgetTop > .widgetName'); + + const $seriesPickerElem = $('<div class="single-metric-view-picker"><div></div></div>'); + + const app = createVueApp({ + render: () => createVNode(SeriesPicker, { + multiselect: false, + selectableColumns: selectableColumns.value, + selectableRows: [], + selectedColumns: selectedColumns.value, + selectedRows: [], + onSelect: ({ columns }: { columns: string[] }) => { + setMetric(columns[0]); + }, + }), + }); + + $widgetName.append($seriesPickerElem); + app.mount($seriesPickerElem.children()[0]); + return app; + } + + let seriesPickerApp: ReturnType<typeof createVueApp>; + + onMounted(() => { + seriesPickerApp = createSeriesPicker(); + }); + + onBeforeUnmount(() => { + $(root.value as HTMLElement) + .closest('.widgetContent') + .off('widget:destroy') + .off('widget:reload'); + $(root.value as HTMLElement) + .closest('div.widget') + .find('.single-metric-view-picker') + .remove(); + seriesPickerApp.unmount(); + }); + + watch(() => props.metric, () => { + onMetricChanged(props.metric); + }); + onMetricChanged(props.metric); + + return { + root, + metricValue, + isLoading, + selectedColumns, + responses, + metricValueUnformatted, + pastValueUnformatted, + metricChangePercent, + pastValue, + metricTranslation, + metricDocumentation, + sparklineParams, + pastPeriod, + selectableColumns, + currentPeriod, + }; + }, +}); +</script> diff --git a/plugins/CoreVisualizations/vue/src/index.ts b/plugins/CoreVisualizations/vue/src/index.ts new file mode 100644 index 0000000000..28caad2a5f --- /dev/null +++ b/plugins/CoreVisualizations/vue/src/index.ts @@ -0,0 +1,12 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import './SeriesPicker/SeriesPicker.adapter'; +import './SingleMetricView/SingleMetricView.adapter'; + +export { default as SeriesPicker } from './SeriesPicker/SeriesPicker.vue'; +export { default as SingleMetricView } from './SingleMetricView/SingleMetricView.vue'; diff --git a/plugins/CoreVue/types/index.d.ts b/plugins/CoreVue/types/index.d.ts index 24fc1c20bc..5e742cdbb1 100644 --- a/plugins/CoreVue/types/index.d.ts +++ b/plugins/CoreVue/types/index.d.ts @@ -87,6 +87,7 @@ declare global { lazyScrollToContent(): void; registerShortcut(key: string, description: string, callback: (event: ExtendedKeyboardEvent) => void): void; compileAngularComponents(selector: JQuery|JQLite|HTMLElement|string, options?: CompileAngularComponentsOptions): void; + calculateEvolution(currentValue: number, pastValue?: number|null): number; sendContentAsDownload(filename: string, content: any, mimeType?: string): void; } diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png b/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png index bcd88012d9..b8f46b1bf3 100644 --- a/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png +++ b/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:173ca9bc58712a4ff73d8fad71aa2c0b78d220cea1cbf62b42989d0ef6b68e6f -size 481773 +oid sha256:51828d341919bed0dab33c8d430d822e0bfdb28140aa19bd36aa05db0348bde5 +size 481845 diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png index e6daf1325b..a85afefe06 100644 --- a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png +++ b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:724ea3a960bdb6df553c7c96e4837a99f4b9dd525b042f50cfad69063587b945 -size 742430 +oid sha256:9ce23f72bf82a2280cffeccd63b9f5829aa834ff1b3fc0d60e67ada992f59292 +size 742383 diff --git a/plugins/UsersManager/vue/dist/UsersManager.umd.js b/plugins/UsersManager/vue/dist/UsersManager.umd.js index e4ab913ac6..6ffaf671af 100644 --- a/plugins/UsersManager/vue/dist/UsersManager.umd.js +++ b/plugins/UsersManager/vue/dist/UsersManager.umd.js @@ -3587,38 +3587,38 @@ NewsletterSettingsvue_type_script_lang_ts.render = NewsletterSettingsvue_type_te scope: {}, directiveName: 'matomoNewsletterSettings' })); -// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-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--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue?vue&type=template&id=d46d01d4 +// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-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--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue?vue&type=template&id=02979bea -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_1 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_1 = { id: "userSettingsTable" }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_2 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_2 = { key: 0 }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_3 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_3 = { id: "languageHelp", class: "inline-help-node" }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_4 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_4 = { target: "_blank", rel: "noreferrer noopener", href: "https://matomo.org/translations/" }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_5 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_5 = { class: "sites_autocomplete" }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_6 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_6 = { class: "modal", id: "confirmChangesWithPassword", ref: "confirmChangesWithPasswordModal" }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_7 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_7 = { class: "modal-content" }; -var PersonalSettingsvue_type_template_id_d46d01d4_hoisted_8 = { +var PersonalSettingsvue_type_template_id_02979bea_hoisted_8 = { class: "modal-footer" }; -function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $props, $setup, $data, $options) { +function PersonalSettingsvue_type_template_id_02979bea_render(_ctx, _cache, $props, $setup, $data, $options) { var _component_Field = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("Field"); var _component_SiteSelector = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SiteSelector"); @@ -3634,7 +3634,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro feature: 'true' }, { default: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(function () { - return [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("form", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { + return [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("form", PersonalSettingsvue_type_template_id_02979bea_hoisted_1, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { uicontrol: "text", name: "username", title: _ctx.translate('General_Username'), @@ -3644,7 +3644,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro return _ctx.username = $event; }), "inline-help": _ctx.translate('UsersManager_YourUsernameCannotBeChanged') - }, null, 8, ["title", "modelValue", "inline-help"])]), _ctx.isUsersAdminEnabled ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_2, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { + }, null, 8, ["title", "modelValue", "inline-help"])]), _ctx.isUsersAdminEnabled ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", PersonalSettingsvue_type_template_id_02979bea_hoisted_2, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { uicontrol: "text", name: "email", "model-value": _ctx.email, @@ -3654,7 +3654,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro }), maxlength: 100, title: _ctx.translate('UsersManager_Email') - }, null, 8, ["model-value", "title"])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_3, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_4, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('LanguagesManager_AboutPiwikTranslations')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { + }, null, 8, ["model-value", "title"])])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_02979bea_hoisted_3, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", PersonalSettingsvue_type_template_id_02979bea_hoisted_4, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('LanguagesManager_AboutPiwikTranslations')), 1)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { uicontrol: "select", name: "language", modelValue: _ctx.language, @@ -3683,7 +3683,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro introduction: _ctx.translate('UsersManager_ReportToLoadByDefault'), title: _ctx.translate('General_AllWebsitesDashboard'), options: _ctx.defaultReportOptions - }, null, 8, ["modelValue", "introduction", "title", "options"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_5, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SiteSelector, { + }, null, 8, ["modelValue", "introduction", "title", "options"])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_02979bea_hoisted_5, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SiteSelector, { modelValue: _ctx.site, "onUpdate:modelValue": _cache[5] || (_cache[5] = function ($event) { return _ctx.site = $event; @@ -3707,7 +3707,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro return _ctx.save(); }), saving: _ctx.loading - }, null, 8, ["saving"]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_6, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_7, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h2", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('UsersManager_ConfirmWithPassword')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { + }, null, 8, ["saving"]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_02979bea_hoisted_6, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_02979bea_hoisted_7, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("h2", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('UsersManager_ConfirmWithPassword')), 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Field, { uicontrol: "password", name: "currentPassword", autocomplete: false, @@ -3717,7 +3717,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro }), "full-width": true, title: _ctx.translate('UsersManager_YourCurrentPassword') - }, null, 8, ["modelValue", "title"])])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_d46d01d4_hoisted_8, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", { + }, null, 8, ["modelValue", "title"])])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", PersonalSettingsvue_type_template_id_02979bea_hoisted_8, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", { href: "", class: "modal-action btn", onClick: _cache[9] || (_cache[9] = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withModifiers"])(function ($event) { @@ -3737,7 +3737,7 @@ function PersonalSettingsvue_type_template_id_d46d01d4_render(_ctx, _cache, $pro _: 1 }, 8, ["content-title"]); } -// CONCATENATED MODULE: ./plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue?vue&type=template&id=d46d01d4 +// CONCATENATED MODULE: ./plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue?vue&type=template&id=02979bea // CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue?vue&type=script&lang=ts @@ -3895,7 +3895,7 @@ var PersonalSettingsvue_type_script_lang_ts_window = window, -PersonalSettingsvue_type_script_lang_ts.render = PersonalSettingsvue_type_template_id_d46d01d4_render +PersonalSettingsvue_type_script_lang_ts.render = PersonalSettingsvue_type_template_id_02979bea_render /* harmony default export */ var PersonalSettings = (PersonalSettingsvue_type_script_lang_ts); // CONCATENATED MODULE: ./plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.adapter.ts diff --git a/plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue b/plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue index 927368a371..c4f88b93d5 100644 --- a/plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue +++ b/plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue @@ -235,6 +235,7 @@ export default defineComponent({ site: { id: this.defaultReportIdSite, name: Matomo.helper.htmlDecode(this.defaultReportSiteName), + }, theDefaultDate: this.defaultDate, loading: false, |