From 0e5d92258d01da1f0bc5c781b26bdbb36d7d4808 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 14 May 2025 00:22:25 +0200 Subject: [PATCH 1/2] Implement flowchart renderer for versions --- src/Controller/SnipController.php | 18 +----- src/Controller/VersionController.php | 9 ++- src/Entity/SnipContent.php | 5 ++ src/Form/SnipType.php | 2 +- .../SnipContent/FlowChartTreeBuilder.php | 37 +++++++++++ src/Service/SnipContent/GitTreeBuilder.php | 61 +++++++++++++++++++ templates/version/index.html.twig | 42 +++++++++---- 7 files changed, 142 insertions(+), 32 deletions(-) create mode 100644 src/Service/SnipContent/FlowChartTreeBuilder.php create mode 100644 src/Service/SnipContent/GitTreeBuilder.php diff --git a/src/Controller/SnipController.php b/src/Controller/SnipController.php index e47c7e2..8ecb177 100644 --- a/src/Controller/SnipController.php +++ b/src/Controller/SnipController.php @@ -81,15 +81,6 @@ class SnipController extends AbstractController { $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); - /** - * Temporary solution to prevent editing of old versions - * It technically fully works, but rendering the version history needs an update first - */ - $isLatest = $snip->getActiveVersion() === $snip->getLatestVersion(); - if (!$isLatest) { - $this->addFlash('error', 'Snip is not the latest version, changes will not be saved.'); - } - $form = $this->createForm(SnipType::class, $snip); $form->add('Save', SubmitType::class); if ($snip->getId()) { @@ -98,11 +89,6 @@ class SnipController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - if (!$isLatest) { - return $this->redirectToRoute('snip_single', [ - 'snip' => $snip->getId(), - ]); - } $this->repository->save($snip); $contentService->update( $snip, @@ -112,9 +98,7 @@ class SnipController extends AbstractController $this->addFlash('success', sprintf('Snip "%s" saved', $snip)); - return $this->redirectToRoute('snip_single', [ - 'snip' => $snip->getId(), - ]); + return $this->redirectToRoute('snip_single', ['snip' => $snip->getId()]); } return $this->render('snip/edit.html.twig', [ diff --git a/src/Controller/VersionController.php b/src/Controller/VersionController.php index 8aa7d2e..c1ebf98 100644 --- a/src/Controller/VersionController.php +++ b/src/Controller/VersionController.php @@ -5,6 +5,7 @@ namespace App\Controller; use App\Entity\Snip; use App\Entity\SnipContent; use App\Security\Voter\SnipVoter; +use App\Service\SnipContent\FlowChartTreeBuilder; use App\Service\SnipContent\SnipContentService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; @@ -18,12 +19,16 @@ class VersionController extends AbstractController ) {} #[Route('/', name: '_index')] - public function index(Snip $snip): Response + public function index(Snip $snip, FlowChartTreeBuilder $builder): Response { $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); - + + $buildTree = $builder->buildTree($snip); + dump($buildTree); return $this->render('version/index.html.twig', [ 'snip' => $snip, +// 'versions' => new GitTreeBuilder($snip)->buildTree($snip->getSnipContents()->first()), + 'versions' => $buildTree, ]); } diff --git a/src/Entity/SnipContent.php b/src/Entity/SnipContent.php index 1cc8305..be182ff 100644 --- a/src/Entity/SnipContent.php +++ b/src/Entity/SnipContent.php @@ -43,6 +43,11 @@ class SnipContent $this->children = new ArrayCollection(); } + public function __toString(): string + { + return $this->name ?? $this->id->toBase32(); + } + public function getId(): ?Ulid { return $this->id; diff --git a/src/Form/SnipType.php b/src/Form/SnipType.php index 685153a..d571130 100644 --- a/src/Form/SnipType.php +++ b/src/Form/SnipType.php @@ -6,7 +6,6 @@ use App\Entity\Snip; use App\Service\SnipParser\ParserFactory; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -36,6 +35,7 @@ class SnipType extends AbstractType ->add('contentName', TextType::class, [ 'label' => 'Change description (optional)', 'mapped' => false, + 'required' => false, ]) ; } diff --git a/src/Service/SnipContent/FlowChartTreeBuilder.php b/src/Service/SnipContent/FlowChartTreeBuilder.php new file mode 100644 index 0000000..792a7f3 --- /dev/null +++ b/src/Service/SnipContent/FlowChartTreeBuilder.php @@ -0,0 +1,37 @@ +getSnipContents() as $content) { + if ($content->getParent()) { + $tree[] = sprintf('%s --> %s', $content->getParent(), $content); + } + } + + foreach ($snip->getSnipContents() as $content) { + $tree[] = sprintf( + 'click %s href "%s"', + $content, + $this->router->generate('version_set', ['snip' => $snip->getId(), 'version' => $content->getId()]) + ); + $tree[] = sprintf('%s@{ shape: rounded }', $content); + } + + $tree[] = sprintf('class %s active', $snip->getActiveVersion()); + + return $tree; + } +} \ No newline at end of file diff --git a/src/Service/SnipContent/GitTreeBuilder.php b/src/Service/SnipContent/GitTreeBuilder.php new file mode 100644 index 0000000..217d9ad --- /dev/null +++ b/src/Service/SnipContent/GitTreeBuilder.php @@ -0,0 +1,61 @@ +activeBranch !== $branch) { + $tree[] = $this->checkout($branch); + } + $commit = sprintf('commit id:"%s"', $content); + if ($this->snip->getActiveVersion() === $content) { + $commit .= ' tag: "active" type: REVERSE'; + } + $tree[] = $commit; + + $first = true; + foreach ($content->getChildren() as $child) { + if (!$first) { + $tree[] = $this->branch($child); + $tree[] = $this->checkout($branch); + } + $first = false; + } + + $first = true; + foreach ($content->getChildren() as $child) { + if ($first) { + $myBranch = $branch; + } else { + $tree[] = $this->checkout($child); + $myBranch = $child; + } + $tree = array_merge($tree, self::buildTree($child, $myBranch)); + $first = false; + } + + return $tree; + } + + private function branch(string $branch): string + { + $this->activeBranch = $branch; + return sprintf('branch %s', $branch); + } + + private function checkout(string $branch): string + { + $this->activeBranch = $branch; + return sprintf('checkout %s', $branch); + } +} \ No newline at end of file diff --git a/templates/version/index.html.twig b/templates/version/index.html.twig index 81a7c20..0808ef8 100644 --- a/templates/version/index.html.twig +++ b/templates/version/index.html.twig @@ -12,17 +12,35 @@ Compare -

-
- {% for version in snip.snipContents|reverse %} - - - {{ include('generic/datetime.badge.html.twig', {datetime: version.id.dateTime}) }} - {% if version.name %}{{ version.name }}{% endif %} - - {{ version.id }} - +
+        flowchart BT
+        {% for versionData in versions %}
+            {{~ versionData ~}}
         {% endfor %}
-    
+ +{% endblock %} + +{% block js %} + {{ parent() }} + + +{% endblock %} + +{% block css %} + {{ parent() }} + {% endblock %} \ No newline at end of file -- 2.43.0 From 283c9ecb271d5648f15ded9ba2a3c27f2376739b Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 15 May 2025 01:15:57 +0200 Subject: [PATCH 2/2] Remove dump --- src/Controller/VersionController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Controller/VersionController.php b/src/Controller/VersionController.php index c1ebf98..96f2b24 100644 --- a/src/Controller/VersionController.php +++ b/src/Controller/VersionController.php @@ -24,7 +24,6 @@ class VersionController extends AbstractController $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); $buildTree = $builder->buildTree($snip); - dump($buildTree); return $this->render('version/index.html.twig', [ 'snip' => $snip, // 'versions' => new GitTreeBuilder($snip)->buildTree($snip->getSnipContents()->first()), -- 2.43.0