Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

* [PR-280](https://github.com/itk-dev/economics/pull/280)
Extended service agreement overview with new and updated fields.
Tweaked form styling.
* [PR-276](https://github.com/itk-dev/economics/pull/276)
Changed to use supercronic instead of woodpecker for crontabs.
* [PR-277](https://github.com/itk-dev/economics/pull/277)
Expand Down
13 changes: 13 additions & 0 deletions assets/controllers/eol-required_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static targets = ["checkbox", "dateField"];

connect() {
this.toggle();
}

toggle() {
this.dateFieldTarget.required = this.checkboxTarget.checked;
}
}
18 changes: 17 additions & 1 deletion assets/styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,15 @@
}

.toggle-label {
@apply relative inline-flex items-center cursor-pointer;
@apply relative inline-flex items-center cursor-pointer select-none;
}

.form-row.select-none {
@apply flex flex-row-reverse justify-end items-center gap-1;
}

.form-row.select-none .label {
@apply mb-0;
}

.selections .choices__list .choices__input {
Expand Down Expand Up @@ -469,4 +477,12 @@
.service_agreement_filter > div.form-default {
grid-template-columns: repeat(8, minmax(0, 1fr));
}

.checkbox-inline-group {
@apply flex items-center;
}

.checkbox-inline-group label {
@apply mr-4 ml-1 text-sm font-medium text-gray-900 dark:text-white select-none cursor-pointer;
}
}
31 changes: 31 additions & 0 deletions migrations/Version20260410104113.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260410104113 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE service_agreement ADD system_owner_notices JSON NOT NULL COMMENT \'(DC2Type:json)\', ADD is_eol TINYINT(1) NOT NULL, ADD leantime_url VARCHAR(255) DEFAULT NULL, ADD client_contact_name VARCHAR(255) DEFAULT NULL, ADD client_contact_email VARCHAR(255) DEFAULT NULL, ADD dedicated_server TINYINT(1) NOT NULL, ADD server_size VARCHAR(255) DEFAULT NULL, ADD cybersecurity_price DOUBLE PRECISION DEFAULT NULL, ADD git_repos LONGTEXT DEFAULT NULL, ADD created_by VARCHAR(255) DEFAULT NULL, ADD updated_by VARCHAR(255) DEFAULT NULL, ADD created_at DATETIME NOT NULL, ADD updated_at DATETIME NOT NULL, DROP system_owner_notice, CHANGE valid_to valid_to DATETIME DEFAULT NULL');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE service_agreement ADD system_owner_notice VARCHAR(255) NOT NULL, DROP system_owner_notices, DROP is_eol, DROP leantime_url, DROP client_contact_name, DROP client_contact_email, DROP dedicated_server, DROP server_size, DROP cybersecurity_price, DROP git_repos, DROP created_by, DROP updated_by, DROP created_at, DROP updated_at, CHANGE valid_to valid_to DATETIME NOT NULL');
}
}
171 changes: 153 additions & 18 deletions src/Entity/ServiceAgreement.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@
namespace App\Entity;

use App\Enum\HostingProviderEnum;
use App\Enum\ServerSizeEnum;
use App\Enum\SystemOwnerNoticeEnum;
use App\Repository\ServiceAgreementRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

#[ORM\Entity(repositoryClass: ServiceAgreementRepository::class)]
class ServiceAgreement
class ServiceAgreement extends AbstractBaseEntity
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;

#[ORM\ManyToOne(targetEntity: Project::class)]
#[ORM\JoinColumn(nullable: false)]
private ?Project $project = null;
Expand Down Expand Up @@ -44,19 +42,38 @@ class ServiceAgreement
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $validFrom = null;

#[ORM\Column(type: Types::DATETIME_MUTABLE)]
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $validTo = null;

#[ORM\Column]
private ?bool $isActive = null;

#[ORM\Column(enumType: SystemOwnerNoticeEnum::class)]
private ?SystemOwnerNoticeEnum $SystemOwnerNotice = null;
#[ORM\Column(type: Types::JSON)]
private array $systemOwnerNotices = [];

public function getId(): ?int
{
return $this->id;
}
#[ORM\Column]
private bool $isEol = false;

#[ORM\Column(length: 255, nullable: true)]
private ?string $leantimeUrl = null;

#[ORM\Column(length: 255, nullable: true)]
private ?string $clientContactName = null;

#[ORM\Column(length: 255, nullable: true)]
private ?string $clientContactEmail = null;

#[ORM\Column]
private bool $dedicatedServer = false;

#[ORM\Column(enumType: ServerSizeEnum::class, nullable: true)]
private ?ServerSizeEnum $serverSize = null;

#[ORM\Column(nullable: true)]
private ?float $cybersecurityPrice = null;

#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $gitRepos = null;

public function getProject(): ?Project
{
Expand Down Expand Up @@ -159,7 +176,7 @@ public function getValidTo(): ?\DateTimeInterface
return $this->validTo;
}

public function setValidTo(\DateTimeInterface $validTo): static
public function setValidTo(?\DateTimeInterface $validTo): static
{
$this->validTo = $validTo;

Expand All @@ -178,15 +195,133 @@ public function setIsActive(bool $isActive): static
return $this;
}

public function getSystemOwnerNotice(): ?SystemOwnerNoticeEnum
/**
* @return SystemOwnerNoticeEnum[]
*/
public function getSystemOwnerNotices(): array
{
return array_map(
fn (string $value) => SystemOwnerNoticeEnum::from($value),
$this->systemOwnerNotices
);
}

/**
* @param SystemOwnerNoticeEnum[] $notices
*/
public function setSystemOwnerNotices(array $notices): static
{
$this->systemOwnerNotices = array_map(
fn (SystemOwnerNoticeEnum $notice) => $notice->value,
$notices
);

return $this;
}

public function isEol(): bool
{
return $this->isEol;
}

public function setIsEol(bool $isEol): static
{
$this->isEol = $isEol;

return $this;
}

public function getLeantimeUrl(): ?string
{
return $this->leantimeUrl;
}

public function setLeantimeUrl(?string $leantimeUrl): static
{
$this->leantimeUrl = $leantimeUrl;

return $this;
}

public function getClientContactName(): ?string
{
return $this->clientContactName;
}

public function setClientContactName(?string $clientContactName): static
{
$this->clientContactName = $clientContactName;

return $this;
}

public function getClientContactEmail(): ?string
{
return $this->clientContactEmail;
}

public function setClientContactEmail(?string $clientContactEmail): static
{
$this->clientContactEmail = $clientContactEmail;

return $this;
}

public function isDedicatedServer(): bool
{
return $this->dedicatedServer;
}

public function setDedicatedServer(bool $dedicatedServer): static
{
$this->dedicatedServer = $dedicatedServer;

return $this;
}

public function getServerSize(): ?ServerSizeEnum
{
return $this->SystemOwnerNotice;
return $this->serverSize;
}

public function setSystemOwnerNotice(SystemOwnerNoticeEnum $SystemOwnerNotice): static
public function setServerSize(?ServerSizeEnum $serverSize): static
{
$this->SystemOwnerNotice = $SystemOwnerNotice;
$this->serverSize = $serverSize;

return $this;
}

public function getCybersecurityPrice(): ?float
{
return $this->cybersecurityPrice;
}

public function setCybersecurityPrice(?float $cybersecurityPrice): static
{
$this->cybersecurityPrice = $cybersecurityPrice;

return $this;
}

public function getGitRepos(): ?string
{
return $this->gitRepos;
}

public function setGitRepos(?string $gitRepos): static
{
$this->gitRepos = $gitRepos;

return $this;
}

#[Assert\Callback]
public function validateValidTo(ExecutionContextInterface $context): void
{
if ($this->isEol && null === $this->validTo) {
$context->buildViolation('service_agreement.valid_to_required_when_eol')
->atPath('validTo')
->addViolation();
}
}
}
11 changes: 11 additions & 0 deletions src/Enum/ServerSizeEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Enum;

enum ServerSizeEnum: string
{
case LILLE = 'lille';
case MELLEM = 'mellem';
case STOR = 'stor';
case CUSTOM = 'custom';
}
6 changes: 3 additions & 3 deletions src/Enum/SystemOwnerNoticeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

enum SystemOwnerNoticeEnum: string
{
case ON_SERVER = 'on_server';
case ON_UPDATE = 'on_update';
case NEVER = 'never';
case SERVERFLYTNING = 'serverflytning';
case SIKKERHEDSPATCH = 'sikkerhedspatch';
case CYBERSIKKERSHEDSOPDATERING = 'cybersikkershedsopdatering';
}
1 change: 0 additions & 1 deletion src/Form/CombinedServiceAgreementType.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'label_attr' => ['class' => 'label toggle-label'],
'help_attr' => ['class' => 'form-help'],
'row_attr' => ['class' => 'form-row select-none'],
'attr' => ['style' => 'margin-left: 10px;'],
'data' => $options['data']['attachCybersecurityAgreement'] ?? false,
])
->add('cybersecurityAgreement', CybersecurityAgreementType::class, [
Expand Down
Loading
Loading