diff --git a/frontend/components/project/ProjectDrawer.vue b/frontend/components/project/ProjectDrawer.vue
index 5007f89..8dc26af 100644
--- a/frontend/components/project/ProjectDrawer.vue
+++ b/frontend/components/project/ProjectDrawer.vue
@@ -64,7 +64,7 @@
-
+
{{ project.archived ? 'Désarchiver' : 'Archiver' }}
+
+
+
@@ -104,6 +118,7 @@ const isOpen = computed({
const isEditing = computed(() => !!props.project)
const isSubmitting = ref(false)
+const confirmDeleteOpen = ref(false)
const { listRepositories } = useGiteaService()
const giteaRepos = ref
([])
@@ -164,7 +179,7 @@ watch(() => props.modelValue, (open) => {
}
})
-const { create, update } = useProjectService()
+const { create, update, remove } = useProjectService()
async function handleSubmit() {
touched.name = true
@@ -213,6 +228,19 @@ async function handleSubmit() {
}
}
+async function handleDelete() {
+ if (!props.project) return
+ isSubmitting.value = true
+ try {
+ await remove(props.project.id)
+ emit('saved')
+ isOpen.value = false
+ } finally {
+ confirmDeleteOpen.value = false
+ isSubmitting.value = false
+ }
+}
+
async function handleArchiveToggle() {
if (!props.project) return
isSubmitting.value = true
diff --git a/frontend/components/ui/ConfirmDeleteProjectModal.vue b/frontend/components/ui/ConfirmDeleteProjectModal.vue
new file mode 100644
index 0000000..8e0fbe8
--- /dev/null
+++ b/frontend/components/ui/ConfirmDeleteProjectModal.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
{{ $t('projects.deleteConfirmTitle') }}
+
+ {{ $t('projects.deleteConfirmMessage') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/i18n/locales/fr.json b/frontend/i18n/locales/fr.json
index 05abaf3..87c72c9 100644
--- a/frontend/i18n/locales/fr.json
+++ b/frontend/i18n/locales/fr.json
@@ -39,7 +39,10 @@
"noArchivedProjects": "Aucun projet archivé.",
"addProject": "Ajouter un projet",
"addProjectShort": "Projet",
- "editProject": "Modifier un projet"
+ "editProject": "Modifier un projet",
+ "deleteConfirmTitle": "Supprimer le projet",
+ "deleteConfirmMessage": "Êtes-vous sûr de vouloir supprimer ce projet ? Cette action est irréversible.",
+ "cannotDelete": "Impossible de supprimer un projet contenant des tickets."
},
"taskStatuses": {
"created": "Statut créé avec succès.",
diff --git a/frontend/services/dto/project.ts b/frontend/services/dto/project.ts
index 7d64ae3..10cbb3c 100644
--- a/frontend/services/dto/project.ts
+++ b/frontend/services/dto/project.ts
@@ -13,6 +13,7 @@ export type Project = {
bookstackShelfId: number | null
bookstackShelfName: string | null
archived: boolean
+ taskCount: number
}
export type ProjectWrite = {
diff --git a/src/Entity/Project.php b/src/Entity/Project.php
index 7e62b9f..0183078 100644
--- a/src/Entity/Project.php
+++ b/src/Entity/Project.php
@@ -13,6 +13,8 @@ use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Repository\ProjectRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Serializer\Attribute\Groups;
@@ -87,6 +89,15 @@ class Project
#[Groups(['project:read', 'project:write'])]
private bool $archived = false;
+ /** @var Collection */
+ #[ORM\OneToMany(targetEntity: Task::class, mappedBy: 'project')]
+ private Collection $tasks;
+
+ public function __construct()
+ {
+ $this->tasks = new ArrayCollection();
+ }
+
public function getId(): ?int
{
return $this->id;
@@ -216,4 +227,10 @@ class Project
return $this;
}
+
+ #[Groups(['project:read'])]
+ public function getTaskCount(): int
+ {
+ return $this->tasks->count();
+ }
}
diff --git a/src/Entity/Task.php b/src/Entity/Task.php
index 22890b7..001c461 100644
--- a/src/Entity/Task.php
+++ b/src/Entity/Task.php
@@ -82,7 +82,7 @@ class Task
#[Groups(['task:read', 'task:write'])]
private ?TaskGroup $group = null;
- #[ORM\ManyToOne(targetEntity: Project::class)]
+ #[ORM\ManyToOne(targetEntity: Project::class, inversedBy: 'tasks')]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
#[Groups(['task:read', 'task:write'])]
private ?Project $project = null;