Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
479a51b
Fix TreeView support for GLPI 11 Custom Assets
BenLasTed Sep 16, 2026
fcc55e9
Add regression test for custom asset definitions
BenLasTed Sep 29, 2026
08d1268
Update CHANGELOG for custom asset filtering
BenLasTed Sep 29, 2026
0bd044f
Apply Rector namespace imports in config class
BenLasTed Sep 29, 2026
64c6499
Fix asset definition visibility in regression test
BenLasTed Sep 29, 2026
ae76d5d
Fix license header in ConfigTest
BenLasTed Sep 29, 2026
047ad2c
Fix syntax error in config class
BenLasTed Sep 29, 2026
c2649ae
Fix custom asset URLs in TreeView
BenLasTed Sep 29, 2026
c8eb6f6
Update changelog for custom assets support
BenLasTed Sep 29, 2026
781601c
Fix regression test profile access
BenLasTed Sep 30, 2026
0c0edf3
test: diagnose custom asset visibility
BenLasTed Sep 30, 2026
eaf64ed
Fix custom asset regression test
BenLasTed Sep 30, 2026
6d3777f
Remove obsolete AssetDefinitionManager guard
BenLasTed Oct 1, 2026
8af8975
Fix AssetDefinition functional test and code style
BenLasTed Oct 1, 2026
3be225c
Fix TreeView GLPI 11 code style
BenLasTed Oct 1, 2026
0c09515
Fix custom asset functional test and code style
BenLasTed Oct 1, 2026
83a26b4
Fix custom asset test session and code style
BenLasTed Oct 2, 2026
1fdd1ca
Fix custom asset definition test setup
BenLasTed Oct 2, 2026
23e0a2f
Fix custom asset definition test
BenLasTed Oct 2, 2026
1190e28
Fix custom asset visibility in functional test
BenLasTed Oct 2, 2026
1828f58
Update ConfigTest.php
BenLasTed Oct 2, 2026
aa88cf0
Update ConfigTest.php
BenLasTed Oct 2, 2026
11d2078
Update ConfigTest.php
BenLasTed Oct 2, 2026
afd18bc
Update ConfigTest.php
BenLasTed Oct 2, 2026
16f4251
Fix custom asset test permissions and CI checks.
BenLasTed Oct 9, 2026
f6f6fef
Fix custom asset test permissions and CI checks.
BenLasTed Oct 9, 2026
0f0c2da
Fix custom asset test permissions and CI checks.
BenLasTed Oct 9, 2026
20eece2
Merge branch 'main' into feature/glpi11-custom-assets
BenLasTed Oct 9, 2026
21dc933
Merge branch 'main' into feature/glpi11-custom-assets
BenLasTed Oct 28, 2026
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Display GLPI 11 Custom Assets in the location tree

### Fixed

- Prevent custom assets from other asset definitions from appearing in the same location
Comment thread
BenLasTed marked this conversation as resolved.
Resolved
- Add Transifex translations link to README

## [1.21.0] - 2026-09-07
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"php": ">=8.2"
},
"config": {
"autoloader-suffix": "PluginTreeview",
"optimize-autoloader": true,
"autoloader-suffix": "PluginTreeview",
"platform": {
Expand Down
29 changes: 22 additions & 7 deletions inc/config.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@
* @link https://github.com/pluginsGLPI/treeview
* -------------------------------------------------------------------------
*/

use Glpi\Application\View\TemplateRenderer;
use Glpi\Asset\Asset;
use Glpi\Asset\AssetDefinitionManager;
use Glpi\DBAL\QueryExpression;

use function Safe\json_encode;

/**
* Contains the display configuration of the treeview
**/
**/
class PluginTreeviewConfig extends CommonDBTM
{
public static $types = [
Expand All @@ -52,10 +55,10 @@ class PluginTreeviewConfig extends CommonDBTM
];

/**
* Display name of itemtype
*
* @return string
**/
* Display name of itemtype
*
* @return string
**/
public static function getTypeName($nb = 0)
{
return __s('Tree view', 'treeview');
Expand Down Expand Up @@ -128,6 +131,11 @@ public static function getTypes($all = false)
// Only allowed types
$types = self::$types;

$types = array_merge(
$types,
AssetDefinitionManager::getInstance()->getCustomObjectClassNames(),
);

foreach ($types as $key => $type) {
if (!class_exists($type) || !is_a($type, CommonDBTM::class, true)) {
continue;
Expand Down Expand Up @@ -336,6 +344,10 @@ public function getNodesFromDb()
'ORDER' => [$itemtable . '.name'],
];

if (is_a($type, Asset::class, true)) {
$criteria['WHERE']['assets_assetdefinitions_id'] = $type::getDefinition()->fields['id'];
}

if ($item->maybeTemplate()) {
$criteria['WHERE']['is_template'] = 0;
}
Expand Down Expand Up @@ -367,7 +379,9 @@ public function getNodesFromDb()
$value = $r['id'];
$getParam = sprintf('?is_deleted=0&criteria[0][field]=%d&criteria[0][searchtype]=equals&criteria[0][value]=%s&search=Rechercher&start=0', $field_num, $value);

$searchUrl = Toolbox::getItemTypeSearchURL($type) . $getParam;
$searchUrl = is_a($type, Asset::class, true)
Comment thread
BenLasTed marked this conversation as resolved.
Resolved
? $type::getSearchURL() . '&' . ltrim($getParam, '?')
: Toolbox::getItemTypeSearchURL($type) . $getParam;

$params = ['itemtype' => $type,
'locations_id' => $value,
Expand Down Expand Up @@ -413,7 +427,8 @@ public function getNodesFromDb()
}
}

$url = Toolbox::getItemTypeFormURL($type) . '?id=' . $r_1['id'];
$url = $type::getFormURLWithID($r_1['id']);

$pic = 'ti ti-chevrons-right';
$name = strtr($i_name, $trans);
$opt = ['url' => $url,
Expand Down
80 changes: 77 additions & 3 deletions tests/Units/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@

use Computer;
use Entity;
use Glpi\Asset\AssetDefinitionManager;
use GlpiPlugin\Treeview\Tests\TreeviewTestCase;
use Location;
use PluginTreeviewConfig;
use Session;

final class ConfigTest extends TreeviewTestCase
Expand Down Expand Up @@ -132,16 +134,88 @@ public function testGetNodesFromDbHidesItemtypeWithoutViewRight(): void
'locations_id' => $location->getID(),
]);

// remove all rights to view computers
$this->removeRightFromProfile('Super-Admin', Computer::$rightname, READ + READ_ASSIGNED + READ_OWNED);
// Remove all rights to view computers.
$this->removeRightFromProfile(
'Super-Admin',
Computer::$rightname,
READ + READ_ASSIGNED + READ_OWNED,
);

try {
$this->login('glpi');
$this->setEntity($entity_id, false);
$output = $this->getTreeOutput($location->getID());

$this->assertStringNotContainsString($computer->fields['name'], $output);
} finally {
$this->addRightToProfile('Super-Admin', Computer::$rightname, READ + READ_ASSIGNED + READ_OWNED);
$this->addRightToProfile(
'Super-Admin',
Computer::$rightname,
READ + READ_ASSIGNED + READ_OWNED,
);
}
}

public function testGetNodesFromDbDoesNotMixAssetDefinitions(): void
{
$this->login();
$entity_id = $this->getTestRootEntity(true);
$profile_id = $_SESSION['glpiactiveprofile']['id'];

$location = $this->createItem(Location::class, [
'name' => 'treeview_asset_loc_' . $this->getUniqueString(),
'entities_id' => $entity_id,
]);

$definition_a = $this->initAssetDefinition(
'treeview_a_' . $this->getUniqueString(),
profiles: [$profile_id => READ],
);
$definition_b = $this->initAssetDefinition(
'treeview_b_' . $this->getUniqueString(),
profiles: [$profile_id => READ],
);

$asset_a = $this->createItem($definition_a->getAssetClassName(), [
'name' => 'treeview_asset_a_' . $this->getUniqueString(),
'entities_id' => $entity_id,
'locations_id' => $location->getID(),
]);
$asset_b = $this->createItem($definition_b->getAssetClassName(), [
'name' => 'treeview_asset_b_' . $this->getUniqueString(),
'entities_id' => $entity_id,
'locations_id' => $location->getID(),
]);

// Refresh the definition manager so that the newly created
// definitions are available to TreeView.
$manager = AssetDefinitionManager::getInstance();
$manager->clearDefinitionsCache();
$manager->bootDefinitions();

// Definition creation stores rights in the database. Reload the
// current profile so that canView() sees these new rights in session.
Session::changeProfile($profile_id);
$this->setEntity($entity_id, false);

$this->assertTrue($asset_a::canView());
$this->assertTrue($asset_b::canView());
$this->assertContains($definition_a->getAssetClassName(), PluginTreeviewConfig::getTypes());
$this->assertContains($definition_b->getAssetClassName(), PluginTreeviewConfig::getTypes());

$output = $this->getTreeOutput($location->getID());

// Both assets share the same database table. Each asset must only
// appear in the tree group corresponding to its own definition.
// Without the assets_assetdefinitions_id filter, each asset would
// appear twice.
$this->assertSame(
1,
substr_count($output, $asset_a->fields['name']),
);
$this->assertSame(
1,
substr_count($output, $asset_b->fields['name']),
);
}
}