Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ tests/units/composer.lock
tests/units/.phpunit.result.cache
tests/qgis-projects/*
!tests/qgis-projects/tests
!tests/qgis-projects/mock_inspection/
!tests/qgis-projects/mock_inspection/*.log
!tests/qgis-projects/webdav
tests/qgis-projects/webdav/test/*
!tests/qgis-projects/webdav/test/logo.png
Expand Down
17 changes: 9 additions & 8 deletions lizmap/modules/admin/controllers/qgis_projects.classic.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,18 @@ public function index()
{
/** @var jResponseHtml */
$rep = $this->getResponse('html');
$rep->title = 'Admin - Lizmap projects';

// Get the project list from the zone
$projectList = jZone::get('project_list', array('repository' => ''));
$rep->title = jLocale::get('admin~admin.project.page.title');

// Set the HTML content
$tpl = new jTpl();
$assign = array(
'projectList' => $projectList,
);
$tpl->assign($assign);
$repoName = $this->param('repository');
// bad repo name, set to null
if (is_null(lizmap::getRepository($repoName ?? ''))) {
$repoName = null;
}
$tpl->assign('repository', $repoName);
$tpl->assign('repositoriesList', lizmap::getRepositoryList(true));
$tpl->assign('baseurl', jUrl::get('qgis_projects:index'));
$rep->body->assign('MAIN', $tpl->fetch('project_list'));
$rep->body->assign('selectedMenuItem', 'lizmap_project_list');

Expand Down
2 changes: 1 addition & 1 deletion lizmap/modules/admin/locales/en_US/admin.UTF-8.properties
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ project.list.column.show.line.hidden.columns=Show/Hide the hidden columns
project.modal.title=Table legend
project.modal.button.close=Close
project.list.no.hidden.column.content=No extra content for this project in the following hidden table columns

project.page.title=QGIS Projects

landingPageContent.authed=Content for authenticated users
landingPageContent.unauthed=Content for unauthenticated users
Expand Down
5 changes: 3 additions & 2 deletions lizmap/modules/admin/templates/project_list.tpl
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{ifacl2 'lizmap.admin.project.list.view'}
{meta_html js $j_basepath.'assets/js/qgis-projects-list.js'}

<h2>{@admin.menu.lizmap.project.list.label@}</h2>

<div id="lizmap_project_list_container">
<div id="lizmap_project_list_container" data-base-url='{$baseurl}'>
<div id="lizmap_project_list">
{$projectList}
{zone 'admin~project_list', ["repository" => $repository, 'repositoriesList' => $repositoriesList]}
</div>
</div>

Expand Down
16 changes: 15 additions & 1 deletion lizmap/modules/admin/templates/project_list_zone.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,24 @@
<!-- Sentence displayed when the user clicks on a line of the projects table
to view the hidden columns data and when there is no data for these columns -->
<span id="lizmap_project_list_no_data_label" style="display: none;">{@admin.project.list.no.hidden.column.content@}</span>

{assign $colspanFromFilter = 9}
{if $hasInspectionData}
{assign $colspanFromFilter = 16}
{/if}
<!-- The table contains the projects data. Datatables is used to improve the UX -->
<table class="lizmap_project_list table table-sm table-bordered {$tableClass}" style="width:100%">
<thead>
<tr>
<th></th>
<th>
<select id='repository-selector' class='form-select form-select-sm'>
<option value="">All</option>
{foreach $repositoriesList as $repo}
<option {if $repository == $repo->getKey() } selected {/if} value="{$repo->getKey()}" >{$repo->getLabel()}</option>
{/foreach}
</select></th>
<th colspan="{$colspanFromFilter}"></th>
</tr>
<tr>
<th></th>
<th>{@admin.project.list.column.repository.label@}</th>
Expand Down
17 changes: 5 additions & 12 deletions lizmap/modules/admin/zones/project_list.zone.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,8 @@ protected function _prepareTpl()
// QGIS server
$qgisServerVersion = $data['qgis_server_info']['metadata']['version'];
$serverVersions['qgis_server_version'] = $qgisServerVersion;
$explode = explode('.', $qgisServerVersion);
// Keep only major and minor version
// Like 3.40
// Fixme, to move in VersionTools
$qgisServerVersionInt = intval($explode[0].str_pad($explode[1], 2, '0', STR_PAD_LEFT));
// Keep only major and minor version as int like 3.40.13 => 340
$qgisServerVersionInt = VersionTools::strVersionToMajMinInt($qgisServerVersion);
$serverVersions['qgis_server_version_int'] = $qgisServerVersionInt;
$serverVersions['qgis_server_version_human_readable'] = VersionTools::qgisMajMinHumanVersion($qgisServerVersionInt);
$serverVersions['qgis_server_version_old'] = VersionTools::qgisMajMinHumanVersion($qgisServerVersionInt - $oldQgisVersionDelta - 2);
Expand Down Expand Up @@ -157,6 +154,7 @@ protected function _prepareTpl()
$this->_tpl->assign('lizmapVersion', $lizmapInfo->version);
$this->_tpl->assign('oldQgisVersionDiff', $oldQgisVersionDelta);
$this->_tpl->assign('lizmapDesktopRecommended', $lizmapDesktopRecommended);
$this->_tpl->assign('repository', $repository);
// Add the application base path to let the template load the CSS and JS assets
$basePath = jApp::urlBasePath();
$this->_tpl->assign('basePath', $basePath);
Expand Down Expand Up @@ -209,13 +207,8 @@ private function getProjectListItem($inspectionDirectoryPath, $projectMetadata)

// Get QGIS project version
$qgisVersionInt = $projectMetadata->getQgisProjectVersion();
// Create a human readable version, but suitable for string ordering
// Ex: 3.06.02 instead of 3.6.2
// Fixme, to move in VersionTools
$qgisVersion = substr($qgisVersionInt, 0, 1);
$qgisVersion .= '.'.ltrim(substr($qgisVersionInt, 1, 2), '');
$qgisVersion .= '.'.ltrim(substr($qgisVersionInt, 3, 2), '');
$projectItem['qgis_version'] = $qgisVersion;
// Create a human readable version, but suitable for string ordering (by js)
$projectItem['qgis_version'] = VersionTools::intVersionToSortableString($qgisVersionInt);
// Integer version: keep only major and minor versions. Ex: 322 for 3.22.04
$projectItem['qgis_version_int'] = (int) substr($qgisVersionInt, 0, 3);

Expand Down
7 changes: 5 additions & 2 deletions lizmap/modules/lizmap/classes/lizmap.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ public static function getTheme()
/**
* Get a list of repository names.
*
* @return string[] List of repositories names
* @return Repository[]|string[] List of repositories names
*/
public static function getRepositoryList()
public static function getRepositoryList(bool $asObject = false)
{
// read the lizmap configuration file
$readConfigPath = parse_ini_file(jApp::varPath().self::$lizmapConfig, true);
Expand All @@ -145,6 +145,9 @@ public static function getRepositoryList()
}
}
self::$repositories = $repositoryList;
if ($asObject) {
return array_map(function ($name) {return lizmap::getRepository($name); }, self::$repositories);
}

return self::$repositories;
}
Expand Down
15 changes: 15 additions & 0 deletions lizmap/modules/lizmap/lib/App/VersionTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ public static function intVersionToSortableString(string $intVersion): string
return $majorVersion.'.'.$minorVersion.'.'.$patchVersion;
}

/**
* Transform a version string to an int version keeping only major and minor,
* ie "3.40.15" into 340, 3.5.6 to 305.
*
* @param string $version The version, for instance "3.40.15"
*
* @return int The major and minor version as int
*/
public static function strVersionToMajMinInt(string $version): int
{
$explode = explode('.', $version);

return intval($explode[0].str_pad($explode[1], 2, '0', STR_PAD_LEFT));
}

/**
* Transform a QGIS version with its name to a sortable int version.
*
Expand Down
10 changes: 6 additions & 4 deletions lizmap/www/assets/js/admin/activate_datatable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ $(document).ready(function () {
// Activate datatable for the project list table
if ($('table.lizmap_project_list').length) {
let has_inspection_data = false;
let columnDeltaForVersion = 0;
if ($('table.lizmap_project_list').hasClass('has_inspection_data')) {
has_inspection_data = true;
columnDeltaForVersion = 4;
}

// Configure the rendering of some columns
var columnDefs = [
// Change lizmap plugin version display
// Change lizmap plugin/QGIS version display, sortable value to human readable
{
"targets": 5,
"targets": [4+columnDeltaForVersion,5+columnDeltaForVersion],
"render": function (data, type, row, meta) {
if (type == 'display') {
// 03.09.00 => 3.9
return data.substr(0, 5).replace(/\.0/g, '.').replace(/^0/, '');
// 03.09.00 => 3.9 (remove useless .00), 03.05.11 => 3.5.11
return data.replace(/\.0/g, '.').replace(/^0/, '').replace(/\.0$/, '');
}
return data;
}
Expand Down
8 changes: 8 additions & 0 deletions lizmap/www/assets/js/qgis-projects-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

document.addEventListener('DOMContentLoaded', () => {
document.getElementById('repository-selector').addEventListener('change', function () {
const baseUrl = document.getElementById('lizmap_project_list_container').dataset.baseUrl;
const repositoryFilter = this.value;
window.location = repositoryFilter ? baseUrl + '?repository=' + repositoryFilter : baseUrl;
});
});
7 changes: 7 additions & 0 deletions tests/docker-conf/phpfpm/lizmapConfig.ini.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,10 @@
label="Repository with bad path"
path="/srv/lzm/tests/qgis-projects/bad/"
allowUserDefinedThemes=0

[repository:mockinspection]
label="Mock inspection"
path="/srv/lzm/tests/qgis-projects/mock_inspection/"
allowUserDefinedThemes=0
accessControlAllowOrigin=
iframeEmbedAllowOrigin=
32 changes: 32 additions & 0 deletions tests/end2end/playwright/admin-qgis-projects.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,36 @@ test.describe('QGIS Projects page', () => {
await expect(dndFormRow.locator(title)).toContainText('dnd_form');
await expect(dndFormRow.locator(title)).not.toContainText('🔒');
});

test('Filter by repository', async ({ page }) => {
const adminPage = new AdminPage(page);
await adminPage.open();
await adminPage.openPage('QGIS projects');
const projects = adminPage.page.locator('#lizmap_project_list');
const allProjectCount = await projects.locator('table tbody tr').count();
expect(allProjectCount).toBeGreaterThan(1);
// select bad respository (0 projects)
await page.locator('#repository-selector').selectOption('badrepository');
await page.waitForURL(/repository=badrepository/);
// datatable show 1 line with class dataTables_empty
expect(projects.locator('table tbody tr')).toHaveCount(1)
expect(projects.locator('table tbody tr td')).toHaveClass('dataTables_empty');

});

test('Check project with inspection', async ({ page }) => {
const adminPage = new AdminPage(page);
await adminPage.open();
await adminPage.openPage('QGIS projects');
const projects = adminPage.page.locator('#lizmap_project_list');
const columnLocator = 'table tbody tr:first-child td';
const projectAdminColCount = 11;
const inspectionDelta = 7;
expect(await projects.locator(columnLocator).count()).toBe(projectAdminColCount+inspectionDelta);
// select testsrepository (no inpection)
await page.locator('#repository-selector').selectOption('testsrepository');
await page.waitForURL(/repository=testsrepository/);
expect(await projects.locator(columnLocator).count()).toBe(projectAdminColCount);

});
});
2 changes: 1 addition & 1 deletion tests/end2end/playwright/requests-api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ test.describe('Connected from context, as an admin',
const json = await checkJson(response);

// Check number of repositories
expect(json).toHaveLength(5);
expect(json).toHaveLength(6);

// Check first repository has expected
expect(json[0].key).toBeDefined();
Expand Down
17 changes: 17 additions & 0 deletions tests/qgis-projects/mock_inspection/.base_layers.qgs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"inspection_timestamp": 1783687903,
"has_inspection_data": true,
"loading_infos": {
"loading_time_ms": 552,
"memory_footprint": 5550
},
"bad_layers_count": 3,
"layers": [
{
"valid": false,
"source" : "source",
"name" : "name"
}
],
"qgis_log": "Lorem ipsm"
}
1 change: 1 addition & 0 deletions tests/qgis-projects/mock_inspection/.base_layers.qgs.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Mock QGIS Log content
Loading
Loading