From 34e0f6262ed040c7d567f6ed33be9584a3ffbbe8 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Tue, 30 Jun 2026 08:13:56 +0200 Subject: [PATCH 1/9] fix(DataSource\Lca\Boaviztapi\Client): type hinting --- src/DataSource/Lca/Boaviztapi/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DataSource/Lca/Boaviztapi/Client.php b/src/DataSource/Lca/Boaviztapi/Client.php index 5eeb0f12..3acbc46b 100644 --- a/src/DataSource/Lca/Boaviztapi/Client.php +++ b/src/DataSource/Lca/Boaviztapi/Client.php @@ -273,7 +273,7 @@ public function parseResponse(array $response, string $scope): array return $impacts; } - protected function parseCriteria(string $name, $impact): ?TrackedFloat + protected function parseCriteria(string $name, array|string $impact): ?TrackedFloat { if ($impact === 'not implemented') { return null; From 1839088f33b70ec275c044c980703c51695b31eb Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Thu, 25 Jun 2026 09:06:58 +0200 Subject: [PATCH 2/9] test: code cleanup --- .../DataSource/CarbonIntensity/ElectricityMaps/ConfigTest.php | 4 ---- tests/units/DataSource/Lca/Boaviztapi/ConfigTest.php | 4 ---- 2 files changed, 8 deletions(-) diff --git a/tests/units/DataSource/CarbonIntensity/ElectricityMaps/ConfigTest.php b/tests/units/DataSource/CarbonIntensity/ElectricityMaps/ConfigTest.php index da22ef07..034a2347 100644 --- a/tests/units/DataSource/CarbonIntensity/ElectricityMaps/ConfigTest.php +++ b/tests/units/DataSource/CarbonIntensity/ElectricityMaps/ConfigTest.php @@ -99,10 +99,6 @@ public function testConfigUpdate(array $input, array $expected) /** @var array $CFG_GLPI */ global $CFG_GLPI; - $CFG_GLPI['plugi:carbon']['lca_datasources'] = [ - Client::class, - ]; - $instance = new Config(); $result = $instance->configUpdate($input); $this->assertEquals($expected, $result); diff --git a/tests/units/DataSource/Lca/Boaviztapi/ConfigTest.php b/tests/units/DataSource/Lca/Boaviztapi/ConfigTest.php index 7f5249e1..ef3a40b7 100644 --- a/tests/units/DataSource/Lca/Boaviztapi/ConfigTest.php +++ b/tests/units/DataSource/Lca/Boaviztapi/ConfigTest.php @@ -124,10 +124,6 @@ public function testConfigUpdate(array $input, array $expected) /** @var array $CFG_GLPI */ global $CFG_GLPI; - $CFG_GLPI['plugi:carbon']['lca_datasources'] = [ - Client::class, - ]; - $result = (new Config())->configUpdate($input); $this->assertEquals($expected, $result); } From e04727605865171e93d1a9a0d86a5e134270a605 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Thu, 25 Jun 2026 14:36:59 +0200 Subject: [PATCH 3/9] feat(Impact\Embodied\Boavizta): support for cloud servers depends on CloudInventory plugin --- phpstan.neon | 2 + setup.php | 3 + src/CloudInventoryConnector.php | 57 +++++++ src/ComputerType.php | 2 + src/DataSource/Lca/Boaviztapi/Client.php | 26 ++++ src/Impact/Embodied/Boavizta/Computer.php | 154 +++++++++++++++---- stubs/OptionalClass.php.stub | 25 +++ templates/environmentalimpact-item.html.twig | 6 + tests/src/CommonTestCase.php | 6 +- 9 files changed, 246 insertions(+), 35 deletions(-) create mode 100644 src/CloudInventoryConnector.php create mode 100644 stubs/OptionalClass.php.stub diff --git a/phpstan.neon b/phpstan.neon index c02769b3..bc4ce357 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,6 +5,7 @@ parameters: bootstrapFiles: - ../../stubs/glpi_constants.php - ../../vendor/autoload.php + - stubs/OptionalClass.php.stub paths: - src - front @@ -17,5 +18,6 @@ parameters: - ../../src stubFiles: - ../../stubs/glpi_constants.php + - ./stubs/OptionalClass.php.stub rules: - GlpiProject\Tools\PHPStan\Rules\GlobalVarTypeRule diff --git a/setup.php b/setup.php index f2aedb35..5bccce42 100644 --- a/setup.php +++ b/setup.php @@ -33,6 +33,7 @@ use Config as GlpiConfig; use CronTask as GlpiCronTask; use Glpi\Plugin\Hooks; +use GlpiPlugin\Carbon\CloudInventoryConnector; use GlpiPlugin\Carbon\Config; use GlpiPlugin\Carbon\CronTask; use GlpiPlugin\Carbon\Dashboard\Grid; @@ -115,6 +116,8 @@ function plugin_carbon_setupHooks() LcaClientFactory::getSecuredConfigs() ); + $PLUGIN_HOOKS[Hooks::POST_INIT]['carbon'] = [CloudInventoryConnector::class, 'checkPluginAvailability']; + // add new cards to the dashboard $PLUGIN_HOOKS[Hooks::DASHBOARD_CARDS]['carbon'] = [Grid::class, 'getDashboardCards']; $PLUGIN_HOOKS[Hooks::DASHBOARD_TYPES]['carbon'] = [Widget::class, 'WidgetTypes']; diff --git a/src/CloudInventoryConnector.php b/src/CloudInventoryConnector.php new file mode 100644 index 00000000..491a8a73 --- /dev/null +++ b/src/CloudInventoryConnector.php @@ -0,0 +1,57 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon; + +use Plugin; + +/** + * Establish the functional bridge between Carbon and the plugin CloudInventory + */ +class CloudInventoryConnector +{ + public static function checkPluginAvailability(): void + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $CFG_GLPI['plugin:carbon']['use_cloudinventory'] = Plugin::isPluginActive('cloudinventory'); + } + + public function pluginAvailable(): bool + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + return $CFG_GLPI['plugin:carbon']['use_cloudinventory'] ?? false; + } +} diff --git a/src/ComputerType.php b/src/ComputerType.php index c20955d7..ce4ede8f 100644 --- a/src/ComputerType.php +++ b/src/ComputerType.php @@ -50,6 +50,7 @@ class ComputerType extends AbstractChildDropdown public const CATEGORY_LAPTOP = 3; public const CATEGORY_TABLET = 4; public const CATEGORY_SMARTPHONE = 5; + public const CATEGORY_CLOUD = 6; public static function getCategories(): array { @@ -60,6 +61,7 @@ public static function getCategories(): array self::CATEGORY_LAPTOP => __('Laptop', 'carbon'), self::CATEGORY_TABLET => __('Tablet', 'carbon'), self::CATEGORY_SMARTPHONE => __('Smartphone', 'carbon'), + self::CATEGORY_CLOUD => __('Cloud server', 'carbon'), ]; } diff --git a/src/DataSource/Lca/Boaviztapi/Client.php b/src/DataSource/Lca/Boaviztapi/Client.php index 3acbc46b..a0f8275e 100644 --- a/src/DataSource/Lca/Boaviztapi/Client.php +++ b/src/DataSource/Lca/Boaviztapi/Client.php @@ -44,6 +44,7 @@ use GlpiPlugin\Carbon\Zone; use Override; use RuntimeException; +use Session; class Client extends AbstractClient { @@ -257,6 +258,16 @@ public static function getZones() public function parseResponse(array $response, string $scope): array { $impacts = []; + if (!isset($response['impacts'])) { + if (Session::getLoginUserID(true)) { + $message = __('An error occured while processing the response from Boaviztapi', 'carbon'); + $message .= '
' . ($response['detail'] ?? 'unknown error'); + Session::addMessageAfterRedirect($message, true, ERROR); + } + trigger_error('Error parsing the response ' . var_export($response, true), E_USER_WARNING); + return $impacts; + } + $types = Type::getImpactTypes(); foreach ($response['impacts'] as $type => $impact) { if (!in_array($type, $types)) { @@ -300,4 +311,19 @@ public static function dropdownBoaviztaZone(string $name, array $options = []) { return Dropdown::showFromArray($name, self::getZones(), $options); } + + /** + * Get instances known types of a cloud provider + * + * @param string $provider + * @return array isntances types + */ + public function getCloudInstances(string $provider): array + { + $response = $this->get('cloud/instance/all_instances', [ + 'query' => ['provider' => $provider], + ]); + + return $response; + } } diff --git a/src/Impact/Embodied/Boavizta/Computer.php b/src/Impact/Embodied/Boavizta/Computer.php index 9d16f684..6da6f865 100644 --- a/src/Impact/Embodied/Boavizta/Computer.php +++ b/src/Impact/Embodied/Boavizta/Computer.php @@ -35,10 +35,19 @@ use CommonDBTM; use Computer as GlpiComputer; +use ComputerModel as GlpiComputerModel; use ComputerType as GlpiComputerType; +use GlpiPlugin\Carbon\CloudInventoryConnector; use GlpiPlugin\Carbon\ComputerType; use GlpiPlugin\Carbon\DataSource\Lca\Boaviztapi\ComputerModelizationAdapterTrait; +use GlpiPlugin\Cloudinventory\Amazon; +use GlpiPlugin\Cloudinventory\Azure; +use GlpiPlugin\Cloudinventory\CloudInstance; +use GlpiPlugin\Cloudinventory\Google; +use GlpiPlugin\Cloudinventory\Ovh; +use GlpiPlugin\Cloudinventory\Scaleway; use Override; +use UnhandledMatchError; class Computer extends AbstractAsset { @@ -48,34 +57,113 @@ class Computer extends AbstractAsset protected string $endpoint = 'server'; + /** + * If the plugin CloudInventory is available, this is an oblect from that + * plugin representing the cloud related data of the computer + */ + protected ?CloudInstance $cloud_instance = null; + + /** + * @var array Description of the asset for querying Boaviztapi + */ + protected array $description = []; + #[Override] protected function doEvaluation(): ?array { - // adapt $this->endpoint depending on the type of computer (server, laptop, ...) $type = $this->getType($this->item); - $this->endpoint = $this->getEndpoint($type); + + $response = null; + $this->chooseEvaluationMode($type); + + // select all impact types $this->endpoint .= '?' . $this->getCriteriasQueryString(); - // Ask for embodied impact only - $handle_hardware = in_array($type, [ - ComputerType::CATEGORY_SERVER, - ComputerType::CATEGORY_DESKTOP, - ComputerType::CATEGORY_UNDEFINED, - ]); - $configuration = $this->analyzeHardware(); - if ($handle_hardware && count($configuration) === 0) { - return null; + // Query Boaviztapi + $response = $this->query($this->description); + + $impacts = $this->client->parseResponse($response, 'embedded'); + return $impacts; + } + + private function chooseEvaluationMode(int $type): string + { + if ($type === ComputerType::CATEGORY_CLOUD) { + $cloud_provider = ''; + switch ($this->cloud_instance->fields['itemtype']) { + case Amazon::class: + $cloud_provider = 'aws'; + break; + case Azure::class: + $cloud_provider = 'azure'; + break; + case Google::class: + $cloud_provider = 'gcp'; + break; + case Ovh::class: + $cloud_provider = 'ovhcloud'; + break; + case Scaleway::class: + $cloud_provider = 'scaleway'; + break; + } + $glpi_computer_model = GlpiComputerModel::getById($this->cloud_instance->fields['computermodels_id']); + if ($glpi_computer_model !== false) { + $instance_types = $this->client->getCloudInstances($cloud_provider); + $model = $this->normalizeModel($cloud_provider, $glpi_computer_model->fields['name']); + if (in_array($model, $instance_types)) { + $this->prepareCloudDescription($cloud_provider, $model); + return 'cloud'; + } + } } - $description = [ - 'configuration' => $configuration, + + $this->prepareHardwareDescription($type); + return 'hardware'; + } + + /** + * Prepare description of the asset for the Boaviztapi query + */ + private function prepareHardwareDescription(int $type): void + { + try { + $this->endpoint = match ($type) { + ComputerType::CATEGORY_SERVER => 'server', + ComputerType::CATEGORY_LAPTOP => 'terminal/laptop', + ComputerType::CATEGORY_TABLET => 'terminal/tablet', + ComputerType::CATEGORY_SMARTPHONE => 'terminal/smartphone', + }; + } catch (UnhandledMatchError $e) { + $this->endpoint = 'terminal/desktop'; + } + + $this->description = [ + 'configuration' => $this->analyzeHardware(), 'usage' => [ 'avg_power' => 0, ], ]; - $response = $this->query($description); - $impacts = $this->client->parseResponse($response, 'embedded'); + } - return $impacts; + /** + * Prepare description of the asset for the Boaviztapi query + * + * @param string $provider + * @param string $model + * @return void + */ + private function prepareCloudDescription(string $provider, string $model) + { + $this->endpoint = 'cloud/instance'; + + $this->description = [ + 'usage' => [ + 'avg_power' => 0, + ], + ]; + $this->description['provider'] = $provider; + $this->description['instance_type'] = $model; } /** @@ -85,6 +173,18 @@ protected function doEvaluation(): ?array */ protected function getType(CommonDBTM $item): int { + $cloudInventory_connector = new CloudInventoryConnector(); + if ($cloudInventory_connector->pluginAvailable()) { + $cloud_instance = new CloudInstance(); + $cloud_instance->getFromDBByCrit([ + 'computers_id' => $item->getID(), + ]); + if (!$cloud_instance->isNewItem()) { + $this->cloud_instance = $cloud_instance; + return ComputerType::CATEGORY_CLOUD; + } + } + $computer_table = GlpiComputer::getTable(); $computer_type_table = ComputerType::getTable(); $glpi_computer_type_table = GlpiComputerType::getTable(); @@ -115,24 +215,14 @@ protected function getType(CommonDBTM $item): int return $computer_type->fields['category']; } - /** - * Get the endpoint to use for the given type - */ - protected function getEndpoint(int $type) + protected function normalizeModel(string $provider, string $model): string { - switch ($type) { - case ComputerType::CATEGORY_SERVER: - return 'server'; - case ComputerType::CATEGORY_LAPTOP: - return 'terminal/laptop'; - case ComputerType::CATEGORY_TABLET: - return 'terminal/tablet'; - case ComputerType::CATEGORY_SMARTPHONE: - return 'terminal/smartphone'; + switch ($provider) { + case 'scaleway': + // CloudInventory sets scaleway models with the prefix "SCW-" + return strtolower(substr($model, 4)); } - // ComputerType::CATEGORY_UNDEFINED - // ComputerType::CATEGORY_DESKTOP - return 'terminal/desktop'; + return $provider; } } diff --git a/stubs/OptionalClass.php.stub b/stubs/OptionalClass.php.stub new file mode 100644 index 00000000..6a363cf0 --- /dev/null +++ b/stubs/OptionalClass.php.stub @@ -0,0 +1,25 @@ + */ + public $fields = []; + + /** + * @param array $criteria + * @return bool + * + * @phpstan-impure + */ + public function getFromDBByCrit(array $criteria): bool {} + + public function isNewItem(): bool {} +} + +class Amazon {} +class Azure {} +class Google {} +class Ovh {} +class Scaleway {} diff --git a/templates/environmentalimpact-item.html.twig b/templates/environmentalimpact-item.html.twig index a499c1ec..574e49ff 100644 --- a/templates/environmentalimpact-item.html.twig +++ b/templates/environmentalimpact-item.html.twig @@ -73,6 +73,12 @@ 'fas fa-chart-pie' ) }} +{% if ((embodied_impact.fields['engine'] is defined) and (embodied_impact.fields['engine_version'] is defined)) %} + {{ fields.smallTitle( + embodied_impact.fields['engine'] ~ ' ' ~ embodied_impact.fields['engine_version'], + ) }} +{% endif %} +
diff --git a/tests/src/CommonTestCase.php b/tests/src/CommonTestCase.php index 35abfb7a..97d2e182 100644 --- a/tests/src/CommonTestCase.php +++ b/tests/src/CommonTestCase.php @@ -64,7 +64,7 @@ class CommonTestCase extends TestCase /** @var int $debugMode save state of GLPI debug mode */ private $debugMode = null; - protected $str = null; + protected ?string $str = null; protected function disableDebug() { @@ -115,7 +115,7 @@ protected function setupGLPIFramework(): void return; } - protected function login($name, $password, $noauto = false) + protected function login(string $name, string $password, $noauto = false) { Session::start(); $auth = new Auth(); @@ -539,7 +539,7 @@ protected function isolateInEntity(): int * * @return mixed */ - protected function callPrivateMethod($instance, string $methodName, ...$args) + protected function callPrivateMethod($instance, string $methodName, mixed ...$args) { $method = new ReflectionMethod($instance, $methodName); if (version_compare(PHP_VERSION, '8.1.0') < 0) { From 31aaca99c7113ff8588a71fd8d5d1243ee82311e Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Wed, 1 Jul 2026 09:05:41 +0200 Subject: [PATCH 4/9] fix(CarbonIntensity): limit downloads only if the limit is set --- src/CarbonIntensity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CarbonIntensity.php b/src/CarbonIntensity.php index 4c9fc7ec..8fc7cde6 100644 --- a/src/CarbonIntensity.php +++ b/src/CarbonIntensity.php @@ -251,7 +251,7 @@ public function downloadOneZone(ClientInterface $data_source, Source_Zone $sourc $gap_end = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $gap['end']); $count = $data_source->fullDownload($source_zone, $gap_start, $gap_end, $this, $limit, $progress_bar); $total_count += $count; - if ($total_count >= $limit) { + if ($limit > 0 && $total_count >= $limit) { return $total_count; } } From cde342c81dde3d6019fe0bea2c60bfe1844ff1de Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Wed, 1 Jul 2026 09:27:48 +0200 Subject: [PATCH 5/9] fix(DataSource\CarbonIntensity): cache only if the extended range end is in the pastwithout this constraint, a download occurring when the +14 hours is in the future leadds to a truncated cache, as some data is not kown --- src/DataSource/CarbonIntensity/ElectricityMaps/Client.php | 4 +++- src/DataSource/CarbonIntensity/Rte/Client.php | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php b/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php index 1c9a6c08..5c31f611 100644 --- a/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php +++ b/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php @@ -377,7 +377,9 @@ public function fetchRange(DateTimeImmutable $start, DateTimeImmutable $stop, So } $downloaded_year_month = $start->format('Y-m'); - if (count($full_response) > 0 && $downloaded_year_month < date('Y-m')) { + if (count($full_response) > 0 && $downloaded_year_month < date('Y-m') && date('j') > 1) { + // Cache only if the month being processed is older than the month of now + // and we are at least the 2nd day of the current month (to handle +14 hours overlap) $json = json_encode($full_response); file_put_contents($cache_file, $json); } diff --git a/src/DataSource/CarbonIntensity/Rte/Client.php b/src/DataSource/CarbonIntensity/Rte/Client.php index ec7b66c7..b93d87a7 100644 --- a/src/DataSource/CarbonIntensity/Rte/Client.php +++ b/src/DataSource/CarbonIntensity/Rte/Client.php @@ -336,8 +336,9 @@ public function fetchRange(DateTimeImmutable $start, DateTimeImmutable $stop, So } } else { $downloaded_year_month = $start->format('Y-m'); - if ($downloaded_year_month < date('Y-m')) { + if (count($response) > 0 && $downloaded_year_month < date('Y-m') && date('j') > 1) { // Cache only if the month being processed is older than the month of now + // and we are at least the 2nd day of the current month (to handle +14 hours overlap) $json = json_encode($response); file_put_contents($cache_file, $json); } From 1d8bf3a551986fd7156c4645f1a72ec58961dbcd Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Wed, 1 Jul 2026 14:37:55 +0200 Subject: [PATCH 6/9] refactor(Impact\Embodied\Boavizta): factorize null usage representation --- src/Impact/Embodied/Boavizta/AbstractAsset.php | 4 ++++ src/Impact/Embodied/Boavizta/Computer.php | 8 ++------ src/Impact/Embodied/Boavizta/Monitor.php | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Impact/Embodied/Boavizta/AbstractAsset.php b/src/Impact/Embodied/Boavizta/AbstractAsset.php index 8cf253c0..3d104e8e 100644 --- a/src/Impact/Embodied/Boavizta/AbstractAsset.php +++ b/src/Impact/Embodied/Boavizta/AbstractAsset.php @@ -55,6 +55,10 @@ abstract class AbstractAsset extends AbstractEmbodiedImpact implements AssetInte /** @var Client instance of the HTTP client */ protected ?Client $client = null; + protected const USAGE_NULL = [ + 'avg_power' => 0, + ]; + // abstract public static function getEngine(CommonDBTM $item): EngineInterface; /** diff --git a/src/Impact/Embodied/Boavizta/Computer.php b/src/Impact/Embodied/Boavizta/Computer.php index 6da6f865..ca1188ca 100644 --- a/src/Impact/Embodied/Boavizta/Computer.php +++ b/src/Impact/Embodied/Boavizta/Computer.php @@ -140,9 +140,7 @@ private function prepareHardwareDescription(int $type): void $this->description = [ 'configuration' => $this->analyzeHardware(), - 'usage' => [ - 'avg_power' => 0, - ], + 'usage' => self::USAGE_NULL, ]; } @@ -158,9 +156,7 @@ private function prepareCloudDescription(string $provider, string $model) $this->endpoint = 'cloud/instance'; $this->description = [ - 'usage' => [ - 'avg_power' => 0, - ], + 'usage' => self::USAGE_NULL, ]; $this->description['provider'] = $provider; $this->description['instance_type'] = $model; diff --git a/src/Impact/Embodied/Boavizta/Monitor.php b/src/Impact/Embodied/Boavizta/Monitor.php index 1e8acdb0..91298400 100644 --- a/src/Impact/Embodied/Boavizta/Monitor.php +++ b/src/Impact/Embodied/Boavizta/Monitor.php @@ -52,9 +52,7 @@ protected function doEvaluation(): ?array $description = [ 'configuration' => $configuration, - 'usage' => [ - 'avg_power' => 0, - ], + 'usage' => self::USAGE_NULL, ]; $response = $this->query($description); $impacts = $this->client->parseResponse($response, 'embedded'); From f920a5854283d1b9ba61f7a03de358848a8ce90c Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Wed, 1 Jul 2026 15:38:30 +0200 Subject: [PATCH 7/9] style(Dashboard\Dashboard): dead code cleanup --- src/Dashboard/Dashboard.php | 18 ------------------ src/Dashboard/Widget.php | 7 ------- 2 files changed, 25 deletions(-) diff --git a/src/Dashboard/Dashboard.php b/src/Dashboard/Dashboard.php index b13b8d7f..ec0d593d 100644 --- a/src/Dashboard/Dashboard.php +++ b/src/Dashboard/Dashboard.php @@ -61,22 +61,4 @@ public static function getTotalPowerPerModel(): array { return Provider::getSumPowerPerModel([ComputerModel::getTableField('power_consumption') => ['>', '0']]); } - - public static function cardCarbonintensityProvider(array $params = []) - { - $default_params = [ - 'label' => __('Carbon dioxyde intensity', 'carbon'), - 'icon' => "fas fa-computer", - 'color' => '#ea9999', - ]; - $params = array_merge($default_params, $params); - - $data = Provider::getCarbonIntensity($params); - - return [ - 'data' => $data, - 'label' => $params['label'], - 'icon' => $params['icon'], - ]; - } } diff --git a/src/Dashboard/Widget.php b/src/Dashboard/Widget.php index e0674257..1d2cd42d 100644 --- a/src/Dashboard/Widget.php +++ b/src/Dashboard/Widget.php @@ -102,13 +102,6 @@ public static function WidgetTypes(?array $types = null): array 'width' => 16, 'height' => 12, ], - 'usage_abiotic_depletion' => [ - 'label' => __('Usage abiotic depletion potential', 'carbon'), - 'function' => self::class . '::displayUsageAbioticDepletion', - 'image' => '', - 'width' => 6, - 'height' => 3, - ], 'impact_criteria_number' => [ 'label' => __('Impact criteria', 'carbon'), From 9044e7d0acb1f2a9539c61f6cdc08e08050a281a Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Fri, 3 Jul 2026 13:46:39 +0200 Subject: [PATCH 8/9] fix(SearchOprions): better group title replace Plugins with the friendly name of the plugin, potentially distinguish the search criteria from other plugins --- src/SearchOptions.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SearchOptions.php b/src/SearchOptions.php index 06df8939..77a66819 100644 --- a/src/SearchOptions.php +++ b/src/SearchOptions.php @@ -130,6 +130,11 @@ public static function getCoreSearchOptions(string $itemtype): array { $sopt = []; + $sopt[] = [ + 'id' => 'carbon', + 'name' => __('Environmental impact', 'carbon'), + ]; + if ($itemtype === GlpiLocation::class) { $sopt[] = [ 'id' => SearchOptions::LOCATION_BOAVIZTA_ZONE, From 3357d365b87f762caa7c77b30ef214d40f1d8201 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Fri, 3 Jul 2026 13:47:09 +0200 Subject: [PATCH 9/9] docs(hook): document a hook function --- hook.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hook.php b/hook.php index 66dd3725..54d99277 100644 --- a/hook.php +++ b/hook.php @@ -295,7 +295,13 @@ function plugin_carbon_hook_pre_purge_assettype(CommonDBTM $item) ]); } -function plugin_carbon_MassiveActions($itemtype) +/** + * Massive actions enumeration hook + * + * @param class-string $itemtype + * @return array + */ +function plugin_carbon_MassiveActions($itemtype): array { switch ($itemtype) { case GlpiComputer::class: