feat: replace the navigation with a dashboard and per-area boards
This commit is contained in:
1 parent
d63df2cc1b
commit
bce8f58be3
26 files changed
+810
-328
No files matched your search
@@ -44,11 +44,11 @@ class BookingControllerTest extends WebTestCase
|
||||
{
|
||||
$this->client->loginUser($this->user('[email protected]'));
|
||||
|
||||
$this->client->request('GET', '/tag/2026-10-01', server: ['HTTP_HX-Request' => 'true']);
|
||||
$this->client->request('GET', '/buchen/schreibtische/tag/2026-10-01', server: ['HTTP_HX-Request' => 'true']);
|
||||
$response = $this->client->getResponse();
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
self::assertSame('/?tag=2026-10-01', $response->headers->get('HX-Push-Url'));
|
||||
self::assertSame('/buchen/schreibtische?tag=2026-10-01', $response->headers->get('HX-Push-Url'));
|
||||
self::assertSame(2, substr_count((string) $response->getContent(), 'hx-swap-oob="true"'));
|
||||
self::assertStringContainsString('id="board-calendar"', (string) $response->getContent());
|
||||
self::assertStringContainsString('id="board-floorplan"', (string) $response->getContent());
|
||||
@@ -58,9 +58,9 @@ class BookingControllerTest extends WebTestCase
|
||||
{
|
||||
$this->client->loginUser($this->user('[email protected]'));
|
||||
|
||||
$this->client->request('GET', '/tag/2026-10-01');
|
||||
$this->client->request('GET', '/buchen/schreibtische/tag/2026-10-01');
|
||||
|
||||
self::assertResponseRedirects('/?tag=2026-10-01');
|
||||
self::assertResponseRedirects('/buchen/schreibtische?tag=2026-10-01');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,7 +205,7 @@ class BookingControllerTest extends WebTestCase
|
||||
$this->em->flush();
|
||||
|
||||
$this->client->loginUser($anna);
|
||||
$crawler = $this->client->request('GET', '/?tag=2026-10-01');
|
||||
$crawler = $this->client->request('GET', '/buchen/schreibtische?tag=2026-10-01');
|
||||
|
||||
self::assertCount(1, $crawler->filter(\sprintf('[hx-get="/buchungen/%d/bearbeiten"]', $booking->getId())));
|
||||
}
|
||||
@@ -351,10 +351,10 @@ class BookingControllerTest extends WebTestCase
|
||||
{
|
||||
$this->client->loginUser($this->user('[email protected]'));
|
||||
|
||||
$this->client->request('GET', '/tag/2026-10-01?von=09:00&bis=13:00', server: ['HTTP_HX-Request' => 'true']);
|
||||
$this->client->request('GET', '/buchen/schreibtische/tag/2026-10-01?von=09:00&bis=13:00', server: ['HTTP_HX-Request' => 'true']);
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
self::assertSame('/?tag=2026-10-01&von=09:00&bis=13:00', $this->client->getResponse()->headers->get('HX-Push-Url'));
|
||||
self::assertSame('/buchen/schreibtische?tag=2026-10-01&von=09:00&bis=13:00', $this->client->getResponse()->headers->get('HX-Push-Url'));
|
||||
}
|
||||
|
||||
public function testOverridingOneOccurrenceLeavesTheSeriesAlone(): void
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Booking\TimeRange;
|
||||
use App\Entity\Booking;
|
||||
use App\Entity\Resource;
|
||||
use App\Entity\ResourceType;
|
||||
use App\Entity\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class DashboardControllerTest extends WebTestCase
|
||||
{
|
||||
private KernelBrowser $client;
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->client = self::createClient();
|
||||
$this->client->disableReboot();
|
||||
$this->em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$this->em->getConnection()->beginTransaction();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->em->getConnection()->rollBack();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The extensibility guarantee, asserted against the enum rather than against a fixed list:
|
||||
* a new ResourceType case must produce a working tile without anyone editing a template.
|
||||
*/
|
||||
public function testThereIsATileForEveryBookableKind(): void
|
||||
{
|
||||
$this->client->loginUser($this->user());
|
||||
$crawler = $this->client->request('GET', '/');
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
|
||||
foreach (ResourceType::cases() as $type) {
|
||||
self::assertCount(
|
||||
1,
|
||||
$crawler->filter(\sprintf('a[href="/buchen/%s"]', $type->slug())),
|
||||
\sprintf('no dashboard tile links to the %s board', $type->slug()),
|
||||
);
|
||||
self::assertStringContainsString($type->plural(), $crawler->html());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The bookings list is only reachable from here now that the sidebar is gone.
|
||||
*/
|
||||
public function testTheDashboardLinksToTheBookingsList(): void
|
||||
{
|
||||
$this->client->loginUser($this->user());
|
||||
$crawler = $this->client->request('GET', '/');
|
||||
|
||||
self::assertCount(1, $crawler->filter('a[href="/buchungen"]'));
|
||||
}
|
||||
|
||||
public function testTheNavigationIsGone(): void
|
||||
{
|
||||
$this->client->loginUser($this->user());
|
||||
$crawler = $this->client->request('GET', '/');
|
||||
|
||||
self::assertCount(0, $crawler->filter('#mobilenav'));
|
||||
self::assertCount(1, $crawler->filter('a[href="/logout"]'));
|
||||
}
|
||||
|
||||
public function testATileCountsWhatIsStillFreeToday(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
$today = new \DateTimeImmutable('today');
|
||||
|
||||
$this->resource('D1');
|
||||
$taken = $this->resource('D2');
|
||||
$this->em->persist(new Booking($this->user('[email protected]'), $taken, $today));
|
||||
$this->em->flush();
|
||||
|
||||
$this->client->loginUser($user);
|
||||
$crawler = $this->client->request('GET', '/');
|
||||
|
||||
$tile = $crawler->filter('a[href="/buchen/schreibtische"]')->text();
|
||||
self::assertStringContainsString('von 2 heute frei', $tile);
|
||||
self::assertStringContainsString('1', $tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* A part-day booking still makes the resource "not free today" -- the dashboard has no span
|
||||
* to qualify the answer with, so it takes the whole day.
|
||||
*/
|
||||
public function testAPartDayBookingCountsAsTakenForTheDay(): void
|
||||
{
|
||||
$desk = $this->resource('D1');
|
||||
$this->em->persist(new Booking($this->user('[email protected]'), $desk, new \DateTimeImmutable('today'), TimeRange::fromMinutes(540, 780)));
|
||||
$this->em->flush();
|
||||
|
||||
$this->client->loginUser($this->user());
|
||||
$crawler = $this->client->request('GET', '/');
|
||||
|
||||
self::assertStringContainsString('heute alles belegt', $crawler->filter('a[href="/buchen/schreibtische"]')->text());
|
||||
}
|
||||
|
||||
public function testYourOwnBookingIsCalledOutOnTheTile(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
$this->em->persist(new Booking($user, $this->resource('D1'), new \DateTimeImmutable('today')));
|
||||
$this->em->flush();
|
||||
|
||||
$this->client->loginUser($user);
|
||||
$crawler = $this->client->request('GET', '/');
|
||||
|
||||
self::assertStringContainsString('D1', $crawler->filter('a[href="/buchen/schreibtische"]')->text());
|
||||
}
|
||||
|
||||
public function testABoardOnlyShowsItsOwnKindOfResource(): void
|
||||
{
|
||||
$this->resource('D1', svgElementId: 'desk-01');
|
||||
$this->resource('P1', ResourceType::PARKING, 'parking-01');
|
||||
|
||||
$this->client->loginUser($this->user());
|
||||
|
||||
$desks = $this->client->request('GET', '/buchen/schreibtische')->html();
|
||||
self::assertStringContainsString('D1', $desks);
|
||||
self::assertStringNotContainsString('P1', $desks);
|
||||
|
||||
$parking = $this->client->request('GET', '/buchen/parkplaetze')->html();
|
||||
self::assertStringContainsString('P1', $parking);
|
||||
self::assertStringNotContainsString('D1', $parking);
|
||||
}
|
||||
|
||||
public function testAnUnknownBookingAreaIsNotFound(): void
|
||||
{
|
||||
$this->client->loginUser($this->user());
|
||||
$this->client->request('GET', '/buchen/fahrraeder');
|
||||
|
||||
self::assertResponseStatusCodeSame(404);
|
||||
}
|
||||
|
||||
public function testABoardWithNothingSetUpSaysSo(): void
|
||||
{
|
||||
$this->client->loginUser($this->user());
|
||||
|
||||
self::assertStringContainsString(
|
||||
'noch nichts eingerichtet',
|
||||
$this->client->request('GET', '/buchen/parkplaetze')->html(),
|
||||
);
|
||||
}
|
||||
|
||||
private function user(string $email = '[email protected]'): User
|
||||
{
|
||||
$user = new User($email, 'Test');
|
||||
$user->setRoles(['ROLE_EMPLOYEE']);
|
||||
$this->em->persist($user);
|
||||
$this->em->flush();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
private function resource(string $label, ResourceType $type = ResourceType::DESK, ?string $svgElementId = null): Resource
|
||||
{
|
||||
$resource = new Resource($type, $label, $svgElementId);
|
||||
$this->em->persist($resource);
|
||||
$this->em->flush();
|
||||
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user