Merge branch 'fix/fix-deletion-attachments' into 'master'

Take permissions into account for deletion of WorkflowAttachment (+ type safety)

See merge request Chill-Projet/chill-bundles!899
This commit is contained in:
2025-10-13 14:12:06 +00:00
7 changed files with 81 additions and 18 deletions

View File

@@ -0,0 +1,6 @@
kind: Fixed
body: '[workflow] take permissions into account to delete the workflow attachment'
time: 2025-10-13T16:05:26.088124301+02:00
custom:
Issue: ""
SchemaChange: No schema change

View File

@@ -36,6 +36,18 @@ export interface GenericDocForAccompanyingPeriod extends GenericDoc {
context: "accompanying-period"; context: "accompanying-period";
} }
export function isGenericDocForAccompanyingPeriod(
doc: GenericDoc,
): doc is GenericDocForAccompanyingPeriod {
return doc.context === "accompanying-period";
}
export function isGenericDocWithStoredObject(
doc: GenericDoc,
): doc is GenericDoc & { storedObject: StoredObject } {
return doc.storedObject !== null;
}
interface BaseMetadataWithHtml extends BaseMetadata { interface BaseMetadataWithHtml extends BaseMetadata {
html: string; html: string;
} }
@@ -44,28 +56,33 @@ export interface GenericDocForAccompanyingCourseDocument
extends GenericDocForAccompanyingPeriod { extends GenericDocForAccompanyingPeriod {
key: "accompanying_course_document"; key: "accompanying_course_document";
metadata: BaseMetadataWithHtml; metadata: BaseMetadataWithHtml;
storedObject: StoredObject;
} }
export interface GenericDocForAccompanyingCourseActivityDocument export interface GenericDocForAccompanyingCourseActivityDocument
extends GenericDocForAccompanyingPeriod { extends GenericDocForAccompanyingPeriod {
key: "accompanying_course_activity_document"; key: "accompanying_course_activity_document";
metadata: BaseMetadataWithHtml; metadata: BaseMetadataWithHtml;
storedObject: StoredObject;
} }
export interface GenericDocForAccompanyingCourseCalendarDocument export interface GenericDocForAccompanyingCourseCalendarDocument
extends GenericDocForAccompanyingPeriod { extends GenericDocForAccompanyingPeriod {
key: "accompanying_course_calendar_document"; key: "accompanying_course_calendar_document";
metadata: BaseMetadataWithHtml; metadata: BaseMetadataWithHtml;
storedObject: StoredObject;
} }
export interface GenericDocForAccompanyingCoursePersonDocument export interface GenericDocForAccompanyingCoursePersonDocument
extends GenericDocForAccompanyingPeriod { extends GenericDocForAccompanyingPeriod {
key: "person_document"; key: "person_document";
metadata: BaseMetadataWithHtml; metadata: BaseMetadataWithHtml;
storedObject: StoredObject;
} }
export interface GenericDocForAccompanyingCourseWorkEvaluationDocument export interface GenericDocForAccompanyingCourseWorkEvaluationDocument
extends GenericDocForAccompanyingPeriod { extends GenericDocForAccompanyingPeriod {
key: "accompanying_period_work_evaluation_document"; key: "accompanying_period_work_evaluation_document";
metadata: BaseMetadataWithHtml; metadata: BaseMetadataWithHtml;
storedObject: StoredObject;
} }

View File

@@ -1,4 +1,7 @@
import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc"; import {
GenericDoc,
isGenericDocWithStoredObject,
} from "ChillDocStoreAssets/types/generic_doc";
import { StoredObject, StoredObjectStatus } from "ChillDocStoreAssets/types"; import { StoredObject, StoredObjectStatus } from "ChillDocStoreAssets/types";
import { Person } from "../../../ChillPersonBundle/Resources/public/types"; import { Person } from "../../../ChillPersonBundle/Resources/public/types";
@@ -203,6 +206,25 @@ export interface WorkflowAttachment {
genericDoc: null | GenericDoc; genericDoc: null | GenericDoc;
} }
export type AttachmentWithDocAndStored = WorkflowAttachment & {
genericDoc: GenericDoc & { storedObject: StoredObject };
};
export function isAttachmentWithDocAndStored(
a: WorkflowAttachment,
): a is AttachmentWithDocAndStored {
return (
isWorkflowAttachmentWithGenericDoc(a) &&
isGenericDocWithStoredObject(a.genericDoc)
);
}
export function isWorkflowAttachmentWithGenericDoc(
attachment: WorkflowAttachment,
): attachment is WorkflowAttachment & { genericDoc: GenericDoc } {
return attachment.genericDoc !== null;
}
export interface Workflow { export interface Workflow {
name: string; name: string;
text: string; text: string;

View File

@@ -6,6 +6,7 @@ import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/gener
import AttachmentList from "ChillMainAssets/vuejs/WorkflowAttachment/Component/AttachmentList.vue"; import AttachmentList from "ChillMainAssets/vuejs/WorkflowAttachment/Component/AttachmentList.vue";
import { GenericDoc } from "ChillDocStoreAssets/types"; import { GenericDoc } from "ChillDocStoreAssets/types";
import { fetchWorkflow } from "ChillMainAssets/lib/workflow/api"; import { fetchWorkflow } from "ChillMainAssets/lib/workflow/api";
import { trans, WORKFLOW_ATTACHMENTS_ADD_AN_ATTACHMENT } from "translator";
interface AppConfig { interface AppConfig {
workflowId: number; workflowId: number;
@@ -83,7 +84,7 @@ const canEditAttachement = computed<boolean>(() => {
<ul v-if="canEditAttachement" class="record_actions"> <ul v-if="canEditAttachement" class="record_actions">
<li> <li>
<button type="button" class="btn btn-create" @click="openModal"> <button type="button" class="btn btn-create" @click="openModal">
Ajouter une pièce jointe {{ trans(WORKFLOW_ATTACHMENTS_ADD_AN_ATTACHMENT) }}
</button> </button>
</li> </li>
</ul> </ul>

View File

@@ -1,7 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { EntityWorkflow, WorkflowAttachment } from "ChillMainAssets/types"; import {
AttachmentWithDocAndStored,
EntityWorkflow,
isAttachmentWithDocAndStored,
WorkflowAttachment,
} from "ChillMainAssets/types";
import GenericDocItemBox from "ChillMainAssets/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue"; import GenericDocItemBox from "ChillMainAssets/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue";
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue"; import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
import { computed } from "vue";
import { trans, WORKFLOW_ATTACHMENTS_NO_ATTACHMENT } from "translator";
interface AttachmentListProps { interface AttachmentListProps {
attachments: WorkflowAttachment[]; attachments: WorkflowAttachment[];
@@ -14,35 +21,43 @@ const emit = defineEmits<{
}>(); }>();
const props = defineProps<AttachmentListProps>(); const props = defineProps<AttachmentListProps>();
const notNullAttachments = computed<AttachmentWithDocAndStored[]>(() =>
props.attachments.filter(
(a: WorkflowAttachment): a is AttachmentWithDocAndStored =>
isAttachmentWithDocAndStored(a),
),
);
const canRemove = computed<boolean>((): boolean => {
if (null === props.workflow) {
return false;
}
return props.workflow._permissions.CHILL_MAIN_WORKFLOW_ATTACHMENT_EDIT;
});
</script> </script>
<template> <template>
<p <p
v-if="props.attachments.length === 0" v-if="notNullAttachments.length === 0"
class="chill-no-data-statement text-center" class="chill-no-data-statement text-center"
> >
Aucune pièce jointe {{ trans(WORKFLOW_ATTACHMENTS_NO_ATTACHMENT) }}
</p> </p>
<!-- TODO translate --> <div v-else class="flex-table">
<div else class="flex-table"> <div v-for="a in notNullAttachments" :key="a.id" class="item-bloc">
<div v-for="a in props.attachments" :key="a.id" class="item-bloc">
<generic-doc-item-box <generic-doc-item-box
v-if="a.genericDoc !== null"
:generic-doc="a.genericDoc" :generic-doc="a.genericDoc"
></generic-doc-item-box> ></generic-doc-item-box>
<div class="item-row separator"> <div class="item-row separator">
<ul class="record_actions"> <ul class="record_actions">
<li v-if="a.genericDoc?.storedObject !== null"> <li>
<document-action-buttons-group <document-action-buttons-group
:stored-object="a.genericDoc.storedObject" :stored-object="a.genericDoc.storedObject"
></document-action-buttons-group> ></document-action-buttons-group>
</li> </li>
<li <li v-if="canRemove">
v-if="
!workflow?._permissions
.CHILL_MAIN_WORKFLOW_ATTACHMENT_EDIT
"
>
<button <button
type="button" type="button"
class="btn btn-delete" class="btn btn-delete"

View File

@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc"; import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc";
interface GenericDocItemBoxProps { interface GenericDocItemBoxProps {
genericDoc: GenericDocForAccompanyingPeriod; genericDoc: GenericDoc;
} }
const props = defineProps<GenericDocItemBoxProps>(); const props = defineProps<GenericDocItemBoxProps>();

View File

@@ -670,6 +670,8 @@ workflow:
attachments: attachments:
title: Pièces jointes title: Pièces jointes
no_attachment: Aucune pièce jointe
Add_an_attachment: Ajouter une pièce jointe
wait: wait:
title: En attente de traitement title: En attente de traitement