feat(machine) : add custom field management on machine detail page

- Fix: return customFieldValues in structure endpoint (was hardcoded null)
- Frontend: add editor to create/edit/delete custom field definitions
- Tests: add integration tests for structure values + definition CRUD

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 18:36:14 +01:00
parent 33fc80cbc2
commit d3cd3fc3ce
4 changed files with 175 additions and 2 deletions

View File

@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace App\Tests\Api\Controller;
use App\Tests\AbstractApiTestCase;
/**
* @internal
*/
class MachineCustomFieldDefinitionTest extends AbstractApiTestCase
{
public function testCreateCustomFieldForMachine(): void
{
$machine = $this->createMachine('Machine CF Create');
$client = $this->createGestionnaireClient();
$client->request('POST', '/api/custom_fields', [
'headers' => ['Content-Type' => 'application/ld+json'],
'json' => [
'name' => 'Tension',
'type' => 'number',
'machine' => self::iri('machines', $machine->getId()),
],
]);
$this->assertResponseStatusCodeSame(201);
$this->assertJsonContains(['name' => 'Tension', 'type' => 'number']);
// Verify via structure endpoint
$client->request('GET', sprintf('/api/machines/%s/structure', $machine->getId()));
$this->assertResponseIsSuccessful();
$data = $client->getResponse()->toArray();
$this->assertArrayHasKey('customFields', $data['machine']);
$this->assertNotEmpty($data['machine']['customFields'], 'customFields should contain the new field');
$found = false;
foreach ($data['machine']['customFields'] as $cf) {
if ('Tension' === $cf['name'] && 'number' === $cf['type']) {
$found = true;
break;
}
}
$this->assertTrue($found, 'Structure should contain the created custom field "Tension"');
}
public function testUpdateCustomFieldForMachine(): void
{
$machine = $this->createMachine('Machine CF Update');
$cf = $this->createCustomField('OldName', 'text', $machine);
$client = $this->createGestionnaireClient();
$client->request('PATCH', self::iri('custom_fields', $cf->getId()), [
'headers' => ['Content-Type' => 'application/merge-patch+json'],
'json' => ['name' => 'NewName'],
]);
$this->assertResponseIsSuccessful();
$this->assertJsonContains(['name' => 'NewName']);
// Verify via structure endpoint
$client->request('GET', sprintf('/api/machines/%s/structure', $machine->getId()));
$this->assertResponseIsSuccessful();
$data = $client->getResponse()->toArray();
$this->assertNotEmpty($data['machine']['customFields']);
$names = array_column($data['machine']['customFields'], 'name');
$this->assertContains('NewName', $names, 'Structure should reflect the updated custom field name');
$this->assertNotContains('OldName', $names, 'Old name should no longer appear');
}
public function testDeleteCustomFieldForMachine(): void
{
$machine = $this->createMachine('Machine CF Delete');
$cf = $this->createCustomField('ToDelete', 'text', $machine);
$client = $this->createGestionnaireClient();
$client->request('DELETE', self::iri('custom_fields', $cf->getId()));
$this->assertResponseStatusCodeSame(204);
// Verify via structure endpoint
$client->request('GET', sprintf('/api/machines/%s/structure', $machine->getId()));
$this->assertResponseIsSuccessful();
$data = $client->getResponse()->toArray();
$this->assertSame([], $data['machine']['customFields'], 'customFields should be empty after deletion');
}
public function testAddCustomFieldsEndpointInitializesValues(): void
{
$machine = $this->createMachine('Machine CF Values');
$cf = $this->createCustomField('Voltage', 'number', $machine);
$cf->setDefaultValue('220');
$em = $this->getEntityManager();
$em->persist($cf);
$em->flush();
$client = $this->createGestionnaireClient();
$client->request('POST', sprintf('/api/machines/%s/add-custom-fields', $machine->getId()));
$this->assertResponseIsSuccessful();
$response = $client->getResponse()->toArray();
$this->assertTrue($response['success']);
$this->assertNotEmpty($response['customFieldValues'], 'customFieldValues should not be empty after add-custom-fields');
// Verify via structure endpoint
$client->request('GET', sprintf('/api/machines/%s/structure', $machine->getId()));
$this->assertResponseIsSuccessful();
$data = $client->getResponse()->toArray();
$this->assertNotEmpty($data['machine']['customFieldValues'], 'Structure should contain initialized custom field values');
$cfv = $data['machine']['customFieldValues'][0];
$this->assertSame('220', $cfv['value'], 'Value should match the default value');
$this->assertSame('Voltage', $cfv['customField']['name']);
}
}