Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d419ada
finishing ux341
chippison Nov 24, 2025
854cb51
removing unused code and trying to add some comments on the code
chippison Nov 24, 2025
e51ef63
adding current segment to the title
chippison Nov 24, 2025
9e7e6e2
reacting to change in 'current' compared segment so that we update title
chippison Nov 24, 2025
7165243
refactoring so that we do not touch updatePeriodParams function that …
chippison Nov 24, 2025
efe5348
updated segementation.js so that we can add the code to change the ti…
chippison Nov 24, 2025
7476c28
adding some stores into global window so that its easier to access in…
chippison Nov 24, 2025
5451267
change the use of deprecated piwik.siteName to piwik.currentSiteName;…
chippison Nov 24, 2025
8ef2c7d
adding built files
chippison Nov 24, 2025
b90574e
putback use of piwik.siteName because piwik.currentSiteName is curren…
chippison Nov 24, 2025
a76532e
fixing issue where both category and subcategory is null on initial l…
chippison Nov 25, 2025
7f4f463
fixing bug where title does not get both category and subcategory on …
chippison Nov 25, 2025
0012ccb
updating built files
chippison Nov 25, 2025
b9cb5e6
make use of function which adds a bunch of logic in getting the url p…
chippison Nov 25, 2025
190d1a9
removed no longer used function (replaced by the new function to upda…
chippison Nov 25, 2025
9c17b1d
adding translation key we will use when re-creating the title
chippison Nov 25, 2025
7de279a
adding the new test
chippison Nov 25, 2025
9705b89
adding a check that date and period strings are not empty before usin…
chippison Nov 25, 2025
7585c6c
made sure to decode url encoded string we get for category and subcat…
chippison Nov 26, 2025
54a3ce4
fixing the issue where tests fail because an error happens when tryin…
chippison Nov 27, 2025
97da281
adding latest built min file
chippison Nov 27, 2025
22c45b6
made changes to the code because some tests broke
chippison Nov 27, 2025
158f6ce
Merge branch '5.x-dev' into ux-341
chippison Nov 27, 2025
02970d2
Doing a lazy load here so to fix the issues when building Vue files a…
chippison Nov 28, 2025
eb18812
removed console logs
chippison Nov 28, 2025
9e72908
Merge branch '5.x-dev' into ux-341
chippison Nov 28, 2025
6c6affd
adding corehome built files
chippison Nov 28, 2025
dab5f73
fixing wrong title
chippison Nov 28, 2025
be4794b
removing the timeout and testing if this works
chippison Nov 30, 2025
9daf06f
adding type MatomoWindow so that its easier to read. removing the 'as…
chippison Nov 30, 2025
27cc76b
Merge branch '5.x-dev' into ux-341
chippison Nov 30, 2025
cd1b54f
cleanup code
chippison Nov 30, 2025
c320bda
checking if this fixes flaky test
chippison Nov 30, 2025
afdf33a
removed the unnecessary space
chippison Nov 30, 2025
5db69bb
making variable and parameter names more descriptive
chippison Dec 1, 2025
8c4b412
Merge branch '5.x-dev' into ux-341
chippison Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/CoreHome/CoreHome.php
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ public function getClientSideTranslationKeys(&$translationKeys)
$translationKeys[] = 'CoreHome_CopyModalNote';
$translationKeys[] = 'CoreHome_CopyX';
$translationKeys[] = 'CoreHome_CopyXDescription';
$translationKeys[] = 'CoreHome_WebAnalyticsReports';

// add admin menu translations
if (
Expand Down
199 changes: 199 additions & 0 deletions plugins/CoreHome/tests/UI/ChangeTitle_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*!
* Matomo - free/libre analytics platform
*
* ChangeTitle UI tests.
*
* @link https://matomo.org
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/

describe('ChangeTitle', function () {
const generalParams = '?module=CoreHome&action=index&idSite=1&period=day&date=2025-11-11';
let url = generalParams+ "&category=Dashboard_Dashboard&subcategory=1";

/**
* Get the query parameters from a URL string.
* We will use this to create the expected title
* @param urlString
* @returns {{category, subcategory, date, segment}}
*/
function extractFilters(urlString) {
const url = new URL(urlString);

// base query params
const params = url.searchParams;
// Matomo sometimes stores params in the hash (`#?foo=bar`), so merge those too.
if (url.hash && url.hash.startsWith('#?')) {
for (const [key, value] of new URLSearchParams(url.hash.slice(2))) {
params.set(key, value); // prefer hash values when present
}
}
return {
category: params.get('category') || '',
subcategory: params.get('subcategory') || '',
date: params.get('date') || '',
segment: params.get('segment') || ''
};
}

/**
* Adding a mapping of category and subcategory ids to their names.
* We just fake/hard-code the names for expected titles.
* @param categoryId
* @param subCategoryId
* @returns {{categoryName: string, subcategoryName: string}}
*/
function getActiveMenuNames(categoryId, subCategoryId) {
let catNameMap = {
'Dashboard_Dashboard': 'Dashboard',
'General_Visitors': 'Visitors',
'General_Actions': 'Behaviour',
};
let subCatNameMap = {
'1': 'D4',
'General_Overview': 'Overview ',
'Actions_SubmenuPagesEntry' : 'Entry pages',
'UserCountryMap_RealTimeMap': 'Real-time Map',
};
let catName = '' , subCatName = '';
if (categoryId !=='') {
catName = catNameMap[categoryId];
}
if (subCategoryId !=='') {
subCatName = subCatNameMap[subCategoryId];
}
return {categoryName: catName, subcategoryName: subCatName};
}

/**
* Adding a mapping of segment ids to their names.
* We just fake/hard-code the names for expected titles.
* @param segmentId
* @returns {string}
*/
function getSegment(segmentId) {
if (!segmentId || segmentId === '') {
return ' - All visits';
}
const segments = {
'browserCode==FF': '<script>_x(50)</script>',
'continentCode==eur': 'From Europe {{_Vue.h.constructor`_x(51)`()}}',
'actions>=2' : 'Multiple actions',
};
return ` - ${segments[segmentId]}`;
}
async function escapeHtml(page, str) {
return await page.evaluate((raw) => window.piwikHelper.htmlEntities(raw), str);
}

/**
* This will try to create the expected title based on what we get from the URL.
* @param catId
* @param subCatId
* @param date
* @param segment
* @returns {Promise<string>}
*/
async function makeTitle(catId, subCatId, date, segment) {
let titleSuffix = 'Web Analytics Reports - Matomo';
let {categoryName, subcategoryName} = getActiveMenuNames(catId, subCatId);
categoryName = await escapeHtml(page, categoryName ?? '');
subcategoryName = await escapeHtml(page, subcategoryName ?? '');
const siteName = await page.evaluate(() => window.piwik.siteName);
if (categoryName === subcategoryName) {
subcategoryName = null;
}
const catTitle = subcategoryName ? ` - ${categoryName} > ${subcategoryName}` : categoryName;
segment = await getSegment(segment);
segment = await escapeHtml(page, segment);
return `${siteName} - ${date}${catTitle}${segment} - ${titleSuffix}`;
}

it ('should show the default title', async function () {
await page.goto(url);
await page.waitForNetworkIdle();
await page.waitForSelector('#dashboard', {visible: true});
const { category, subcategory, date, segment } = extractFilters(page.url());
let currentTitle = await page.title();
let title = await makeTitle(category, subcategory, date, segment);
expect(currentTitle).to.equal(title);
});

/** We just go through some known categories and subcategories to make sure the title changes accordingly. */
it ('should change the title based on new category and subcategory when clicking pages', async function () {
await page.click('div.reportingMenu ul.navbar li[data-category-id="General_Actions"]');
await page.waitForNetworkIdle();
await page.click('div.reportingMenu ul.navbar li[data-category-id="General_Actions"] ul li:nth-of-type(2)');
await page.waitForNetworkIdle();
let { category, subcategory, date, segment } = extractFilters(page.url());
let title = await makeTitle(category, subcategory, date, segment);
let currentTitle = await page.title();
expect(currentTitle).to.equal(title);

await page.click('div.reportingMenu ul.navbar li[data-category-id="General_Visitors"]');
await page.waitForNetworkIdle();
await page.click('div.reportingMenu ul.navbar li[data-category-id="General_Visitors"] ul li:nth-of-type(4)');
await page.waitForNetworkIdle();
let { category: category2, subcategory: subcategory2, date: date2, segment: segment2 } = extractFilters(page.url());
title = await makeTitle(category2, subcategory2, date2, segment2);
currentTitle = await page.title();
expect(currentTitle).to.equal(title);
});

it ('should change the title if date changes', async function () {
let newdate = '2025-04-15';
await page.goto(`${url}#?date=${newdate}`);
await page.waitForNetworkIdle();
let theUrl = new URL(page.url());
const { category, subcategory, date, segment } = extractFilters(page.url());
let title = await makeTitle(category, subcategory, date, segment);
let currentTitle = await page.title();
expect(currentTitle).to.equal(title);
});

/** We go through the segments and make sure the title changes accordingly. */
it ('should change the title if new segment is chosen', async function () {
await page.click('div.segmentEditorPanel div.segmentListContainer div.segmentationContainer a.title');
await page.waitForNetworkIdle();
let segmentDataDef = 'continentCode==eur';
let me = await page.waitForSelector(`div.segmentationContainer div.segmentList ul li:nth-of-type(3)`);
await me.click();
await page.waitForNetworkIdle();
const { category, subcategory, date, segment } = extractFilters(page.url());
let title = await makeTitle(category, subcategory, date, segment);
let currentTitle = await page.title();
expect(currentTitle).to.equal(title);

await page.click('div.segmentEditorPanel div.segmentListContainer div.segmentationContainer a.title');
await page.waitForNetworkIdle();
segmentDataDef = 'browserCode==FF';
me = await page.waitForSelector(`div.segmentationContainer div.segmentList ul li:nth-of-type(2)`);
await me.click();
await page.waitForNetworkIdle();
let { category: category2, subcategory: subcategory2, date: date2, segment: segment2 } = extractFilters(page.url());
title = await makeTitle(category2, subcategory2, date2, segment2);
currentTitle = await page.title();
expect(currentTitle).to.equal(title);

await page.click('div.segmentEditorPanel div.segmentListContainer div.segmentationContainer a.title');
await page.waitForNetworkIdle();
me = await page.waitForSelector(`div.segmentationContainer div.segmentList ul li:nth-of-type(1)`);
await me.click();
await page.waitForNetworkIdle();
let { category: category3, subcategory: subcategory3, date: date3, segment: segment3 } = extractFilters(page.url());
title = await makeTitle(category3, subcategory3, date3, segment3);
currentTitle = await page.title();
expect(currentTitle).to.equal(title);

await page.click('div.segmentEditorPanel div.segmentListContainer div.segmentationContainer a.title');
await page.waitForNetworkIdle();
me = await page.waitForSelector(`div.segmentationContainer div.segmentList ul li:nth-of-type(4)`);
await me.click();
await page.waitForNetworkIdle();
let { category: category4, subcategory: subcategory4, date: date4, segment: segment4 } = extractFilters(page.url());
title = await makeTitle(category4, subcategory4, date4, segment4);
currentTitle = await page.title();
expect(currentTitle).to.equal(title);
});

});
112 changes: 99 additions & 13 deletions plugins/CoreHome/vue/dist/CoreHome.umd.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading