Compare commits

...

50 Commits

Author SHA1 Message Date
b5c9e65986 Merge branch 'refs/heads/master' into 321-text-editor
# Conflicts:
#	src/Bundle/ChillMainBundle/Resources/public/module/ckeditor5/editor_config.ts
#	src/Bundle/ChillMainBundle/Resources/public/module/ckeditor5/index.ts
#	src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Comment.vue
#	src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Resources/WriteComment.vue
#	src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue
#	src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/FormEvaluation.vue
#	src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/MemberDetails.vue
#	src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/PersonComment.vue
#	yarn.lock
2025-05-21 20:03:14 +02:00
8b2af35e97 Fix typo 2025-05-21 17:57:35 +02:00
dc44c46667 Fix SocialActionCSVExporterTest.php 2025-05-21 09:29:25 +02:00
ba571c1a69 Merge branch 'master' of https://gitlab.com/Chill-Projet/chill-bundles 2025-05-20 10:04:53 +02:00
6a364705f2 Git add desactivation date for social issue csv export 2025-05-20 09:57:07 +02:00
b6d454691a Git add desactivation date for social action csv export 2025-05-20 09:38:39 +02:00
6d7a6932a9 Merge branch '365-correct-activities-works-counters' into 'master'
#365 correct works counter in acc course summary

Closes #365

See merge request Chill-Projet/chill-bundles!826
2025-05-16 14:40:20 +00:00
juminet
2faf194b15 #365 correct works counter in acc course summary 2025-05-16 14:40:19 +00:00
f207599d86 Merge branch '352-remove-wopi-link-module' into 'master'
Resolve "Code mort: module wopi-link semble inutilisé"

Closes #352

See merge request Chill-Projet/chill-bundles!824
2025-05-16 08:33:57 +00:00
b0959f8cc5 Resolve "Code mort: module wopi-link semble inutilisé" 2025-05-16 08:33:56 +00:00
4c5dee5f0a Fix pipeline 2025-05-14 17:31:48 +02:00
f6c98aa0d5 Add missing translation for user_group.no_user_groups 2025-05-14 14:53:50 +02:00
6d13d184d5 Merge branch 'master' of https://gitlab.com/Chill-Projet/chill-bundles 2025-05-14 13:57:22 +02:00
af36eccfaf Allow more characters for maritalstatus id 2025-05-14 13:56:36 +02:00
483a20a43f Merge branch '374-task-default-filters' into 'master'
Resolve "Module tâche: enlever les filtres par défaut"

Closes #374

See merge request Chill-Projet/chill-bundles!819
2025-05-13 08:59:01 +00:00
6d8e2ad825 Resolve "Module tâche: enlever les filtres par défaut" 2025-05-13 08:59:01 +00:00
86388a63a8 Merge branch '381-uncoherent-display-persons-acc-course-works' into 'master'
381 display previous person participation in acc course work

Closes #381

See merge request Chill-Projet/chill-bundles!823
2025-05-13 08:45:38 +00:00
juminet
5ea55ebfe5 381 display previous person participation in acc course work 2025-05-13 08:45:38 +00:00
f97dc8f931 Merge branch '377-document-file-name' into 'master'
377 - add the document filename to document title when uploading a new document

Closes #377

See merge request Chill-Projet/chill-bundles!821
2025-05-13 08:30:31 +00:00
juminet
a9c3aab528 377 - add the document filename to document title when uploading a new document 2025-05-13 08:30:30 +00:00
1181377bd6 Merge branch '376-typeerror-doc-history' into 'master'
#376 prevent typerror in doc-history + improve display of document history

Closes #376

See merge request Chill-Projet/chill-bundles!820
2025-05-13 07:50:53 +00:00
juminet
2275b7c560 #376 prevent typerror in doc-history + improve display of document history 2025-05-13 07:50:52 +00:00
4a8d298ae5 Fix typing error for the display of text in calendar events 2025-05-05 10:42:04 +02:00
3e7f03d331 Add possibility to cancel a workflow if there is a pending signature [ci-skip] 2025-04-17 14:23:32 +02:00
2dcce7b826 Remove dumps 2025-02-25 15:29:45 +01:00
dcd1777a70 Pass content of the textEditor to the symfony form 2025-02-17 16:25:17 +01:00
a6eb28175a Revert backend to original state and load commentEditor vue app anytime CommentType form field is used 2025-02-17 14:13:07 +01:00
7d78512823 Change symfony form back to original 2025-02-17 13:11:03 +01:00
d0cd4792d6 Fix dynamicEntityPicker: declare variables 2025-02-13 15:02:06 +01:00
6d196ead94 Merge branch '321-text-editor' of https://gitlab.com/Chill-Projet/chill-bundles into 321-text-editor 2025-02-13 14:49:51 +01:00
4047d5fd5b WIP Allow for comment content to be submitted to backend 2025-02-13 14:49:33 +01:00
9aac80d834 Change logic to allow as many comment vue apps to be charged on same page as needed 2025-02-13 14:49:33 +01:00
7560dc57c6 Remove comment editor component from Activity vue app 2025-02-13 14:49:33 +01:00
10314845f6 Turn component into a small vue app and add public private comment logic 2025-02-13 14:49:33 +01:00
9b84bc4d69 Use update ckeditor5 2025-02-13 14:49:33 +01:00
a2fcf039be Refactor CKEditor integration across application
Replaced `ClassicEditor` with a consistent `classicEditor` and added centralized editor configuration using `editorConfig`. Simplified webpack configuration by removing CKEditor-specific setups and dependencies, improving maintainability.
2025-02-13 14:49:33 +01:00
b4d887a372 upgrade ckeditor 2025-02-13 14:49:32 +01:00
0aaa7122da upgrade ckeditor/vue 2025-02-13 14:49:32 +01:00
1bc7f85874 Implement localStorage and toggling of simple/rich text editor 2025-02-13 14:49:32 +01:00
1d2fd000aa Setup new component for text editor 2025-02-13 14:49:32 +01:00
506df432b0 WIP Allow for comment content to be submitted to backend 2025-02-06 16:07:40 +01:00
c32c18b0e2 Change logic to allow as many comment vue apps to be charged on same page as needed 2025-02-06 15:10:49 +01:00
321d569ee9 Remove comment editor component from Activity vue app 2025-02-06 14:32:22 +01:00
cd40eb3932 Turn component into a small vue app and add public private comment logic 2025-02-06 12:46:19 +01:00
f0f2531fa3 Use update ckeditor5 2025-02-06 10:33:32 +01:00
183a220e7b Refactor CKEditor integration across application
Replaced `ClassicEditor` with a consistent `classicEditor` and added centralized editor configuration using `editorConfig`. Simplified webpack configuration by removing CKEditor-specific setups and dependencies, improving maintainability.
2025-02-06 10:33:32 +01:00
9df127a82c upgrade ckeditor 2025-02-06 10:33:32 +01:00
04a1412562 upgrade ckeditor/vue 2025-02-06 10:33:32 +01:00
3aef0a185e Implement localStorage and toggling of simple/rich text editor 2025-02-06 10:33:32 +01:00
578bce31b9 Setup new component for text editor 2025-02-06 10:33:32 +01:00
52 changed files with 447 additions and 367 deletions

View File

@@ -0,0 +1,6 @@
kind: DX
body: Remove dead code for wopi-link module
time: 2025-04-30T14:45:50.406111606+02:00
custom:
Issue: "352"
SchemaChange: No schema change

View File

@@ -0,0 +1,7 @@
kind: Feature
body: Add the document file name to the document title when a user upload a document,
unless there is already a document title.
time: 2025-04-24T14:22:11.800975422+02:00
custom:
Issue: "377"
SchemaChange: No schema change

View File

@@ -0,0 +1,6 @@
kind: Feature
body: Add desactivation date for social action and issue csv export
time: 2025-05-20T09:56:28.108941934+02:00
custom:
Issue: ""
SchemaChange: No schema change

View File

@@ -0,0 +1,7 @@
kind: Fixed
body: trying to prevent bug of typeerror in doc-history + improved display of document
history
time: 2025-04-24T13:39:43.878468232+02:00
custom:
Issue: "376"
SchemaChange: No schema change

View File

@@ -0,0 +1,7 @@
kind: Fixed
body: Display previous participation in acc course work even if the person has left
the acc course
time: 2025-04-24T16:37:46.970203594+02:00
custom:
Issue: "381"
SchemaChange: No schema change

View File

@@ -0,0 +1,6 @@
kind: Fixed
body: Fix display of text in calendar events
time: 2025-05-05T10:27:15.461493066+02:00
custom:
Issue: "372"
SchemaChange: No schema change

View File

@@ -0,0 +1,6 @@
kind: Fixed
body: Add missing translation for user_group.no_user_groups
time: 2025-05-14T14:53:39.53927329+02:00
custom:
Issue: ""
SchemaChange: No schema change

View File

@@ -0,0 +1,6 @@
kind: UX
body: Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page
time: 2025-04-23T17:26:24.45777387+02:00
custom:
Issue: "374"
SchemaChange: No schema change

View File

@@ -220,6 +220,7 @@ framework:
- attenteModification - attenteModification
- attenteMiseEnForme - attenteMiseEnForme
- attenteValidationMiseEnForme - attenteValidationMiseEnForme
- attenteSignature
- attenteVisa - attenteVisa
- postSignature - postSignature
- attenteTraitement - attenteTraitement

View File

@@ -11,6 +11,7 @@
"@hotwired/stimulus": "^3.0.0", "@hotwired/stimulus": "^3.0.0",
"@luminateone/eslint-baseline": "^1.0.9", "@luminateone/eslint-baseline": "^1.0.9",
"@symfony/stimulus-bridge": "^3.2.0", "@symfony/stimulus-bridge": "^3.2.0",
"@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets",
"@symfony/webpack-encore": "^4.1.0", "@symfony/webpack-encore": "^4.1.0",
"@tsconfig/node20": "^20.1.4", "@tsconfig/node20": "^20.1.4",
"@types/dompurify": "^3.0.5", "@types/dompurify": "^3.0.5",

View File

@@ -11,7 +11,7 @@ import Location from "./components/Location.vue";
export default { export default {
name: "App", name: "App",
props: ["hasSocialIssues", "hasLocation", "hasPerson"], props: ["hasSocialIssues", "hasLocation", "hasPerson", "isSimpleEditor"],
components: { components: {
ConcernedGroups, ConcernedGroups,
SocialIssuesAcc, SocialIssuesAcc,

View File

@@ -14,18 +14,21 @@ const i18n = _createI18n(activityMessages);
const hasSocialIssues = document.querySelector("#social-issues-acc") !== null; const hasSocialIssues = document.querySelector("#social-issues-acc") !== null;
const hasLocation = document.querySelector("#location") !== null; const hasLocation = document.querySelector("#location") !== null;
const hasPerson = document.querySelector("#add-persons") !== null; const hasPerson = document.querySelector("#add-persons") !== null;
const isSimpleEditor = true;
const app = createApp({ const app = createApp({
template: `<app template: `<app
:hasSocialIssues="hasSocialIssues" :hasSocialIssues="hasSocialIssues"
:hasLocation="hasLocation" :hasLocation="hasLocation"
:hasPerson="hasPerson" :hasPerson="hasPerson"
:isSimpleEditor = "isSimpleEditor"
></app>`, ></app>`,
data() { data() {
return { return {
hasSocialIssues, hasSocialIssues,
hasLocation, hasLocation,
hasPerson, hasPerson,
isSimpleEditor
}; };
}, },
}) })

View File

@@ -126,4 +126,4 @@
{% block css %} {% block css %}
{{ encore_entry_link_tags('mod_pickentity_type') }} {{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %} {% endblock %}

View File

@@ -96,23 +96,23 @@
</div> </div>
</div> </div>
<FullCalendar :options="calendarOptions" ref="calendarRef"> <FullCalendar :options="calendarOptions" ref="calendarRef">
<template v-slot:eventContent="{ arg }: { arg: { event: EventApi } }"> <template v-slot:eventContent="{ event }">
<span :class="eventClasses(arg.event)"> <span :class="eventClasses(event)">
<b v-if="arg.event.extendedProps.is === 'remote'">{{ <b v-if="event.extendedProps.is === 'remote'">{{
arg.event.title event.title
}}</b> }}</b>
<b v-else-if="arg.event.extendedProps.is === 'range'" <b v-else-if="event.extendedProps.is === 'range'"
>{{ arg.event.startStr }} - >{{ formatDate(event.startStr) }} -
{{ arg.event.extendedProps.locationName }}</b {{ event.extendedProps.locationName }}</b
> >
<b v-else-if="arg.event.extendedProps.is === 'local'">{{ <b v-else-if="event.extendedProps.is === 'local'">{{
arg.event.title event.title
}}</b> }}</b>
<b v-else>no 'is'</b> <b v-else>no 'is'</b>
<a <a
v-if="arg.event.extendedProps.is === 'range'" v-if="event.extendedProps.is === 'range'"
class="fa fa-fw fa-times delete" class="fa fa-fw fa-times delete"
@click.prevent="onClickDelete(arg.event)" @click.prevent="onClickDelete(event)"
> >
</a> </a>
</span> </span>
@@ -221,13 +221,12 @@ import type {
DatesSetArg, DatesSetArg,
EventInput, EventInput,
} from "@fullcalendar/core"; } from "@fullcalendar/core";
import { reactive, computed, ref, onMounted } from "vue"; import { computed, ref, onMounted } from "vue";
import { useStore } from "vuex"; import { useStore } from "vuex";
import { key } from "./store"; import { key } from "./store";
import FullCalendar from "@fullcalendar/vue3"; import FullCalendar from "@fullcalendar/vue3";
import frLocale from "@fullcalendar/core/locales/fr"; import frLocale from "@fullcalendar/core/locales/fr";
import interactionPlugin, { import interactionPlugin, {
DropArg,
EventResizeDoneArg, EventResizeDoneArg,
} from "@fullcalendar/interaction"; } from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid"; import timeGridPlugin from "@fullcalendar/timegrid";
@@ -237,19 +236,13 @@ import {
EventDropArg, EventDropArg,
EventClickArg, EventClickArg,
} from "@fullcalendar/core"; } from "@fullcalendar/core";
import { import { dateToISO, ISOToDate } from "ChillMainAssets/chill/js/date";
dateToISO,
ISOToDate,
} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
import VueMultiselect from "vue-multiselect"; import VueMultiselect from "vue-multiselect";
import { Location } from "../../../../../ChillMainBundle/Resources/public/types"; import { Location } from "ChillMainAssets/types";
import EditLocation from "./Components/EditLocation.vue"; import EditLocation from "./Components/EditLocation.vue";
import { useI18n } from "vue-i18n";
const store = useStore(key); const store = useStore(key);
const { t } = useI18n();
const showWeekends = ref(false); const showWeekends = ref(false);
const slotDuration = ref("00:15:00"); const slotDuration = ref("00:15:00");
const slotMinTime = ref("09:00:00"); const slotMinTime = ref("09:00:00");
@@ -301,6 +294,11 @@ const nextWeeks = computed((): Weeks[] =>
}), }),
); );
const formatDate = (datetime: string) => {
console.log(typeof datetime);
return ISOToDate(datetime);
};
const baseOptions = ref<CalendarOptions>({ const baseOptions = ref<CalendarOptions>({
locale: frLocale, locale: frLocale,
plugins: [interactionPlugin, timeGridPlugin], plugins: [interactionPlugin, timeGridPlugin],
@@ -353,7 +351,7 @@ const pickedLocation = computed<Location | null>({
* return the show classes for the event * return the show classes for the event
* @param arg * @param arg
*/ */
const eventClasses = function (arg: EventApi): object { const eventClasses = function (): object {
return { calendarRangeItems: true }; return { calendarRangeItems: true };
}; };
@@ -431,7 +429,6 @@ function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
if (payload.event.extendedProps.is !== "range") { if (payload.event.extendedProps.is !== "range") {
return; return;
} }
const changedEvent = payload.event;
store.dispatch("calendarRanges/patchRangeTime", { store.dispatch("calendarRanges/patchRangeTime", {
calendarRangeId: payload.event.extendedProps.calendarRangeId, calendarRangeId: payload.event.extendedProps.calendarRangeId,

View File

@@ -10,6 +10,9 @@ const startApp = (
collectionEntry: null | HTMLLIElement, collectionEntry: null | HTMLLIElement,
): void => { ): void => {
console.log("app started", divElement); console.log("app started", divElement);
const inputTitle = collectionEntry?.querySelector("input[type='text']");
const input_stored_object: HTMLInputElement | null = const input_stored_object: HTMLInputElement | null =
divElement.querySelector("input[data-stored-object]"); divElement.querySelector("input[data-stored-object]");
if (null === input_stored_object) { if (null === input_stored_object) {
@@ -26,9 +29,10 @@ const startApp = (
const app = createApp({ const app = createApp({
template: template:
'<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>', '<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>',
data(vm) { data() {
return { return {
existingDoc: existingDoc, existingDoc: existingDoc,
inputTitle: inputTitle,
}; };
}, },
components: { components: {
@@ -38,10 +42,13 @@ const startApp = (
addDocument: function ({ addDocument: function ({
stored_object, stored_object,
stored_object_version, stored_object_version,
file_name,
}: { }: {
stored_object: StoredObject; stored_object: StoredObject;
stored_object_version: StoredObjectVersion; stored_object_version: StoredObjectVersion;
file_name: string;
}): void { }): void {
stored_object.title = file_name;
console.log("object added", stored_object); console.log("object added", stored_object);
console.log("version added", stored_object_version); console.log("version added", stored_object_version);
this.$data.existingDoc = stored_object; this.$data.existingDoc = stored_object;
@@ -49,6 +56,11 @@ const startApp = (
input_stored_object.value = JSON.stringify( input_stored_object.value = JSON.stringify(
this.$data.existingDoc, this.$data.existingDoc,
); );
if (this.$data.inputTitle) {
if (!this.$data.inputTitle?.value) {
this.$data.inputTitle.value = file_name;
}
}
}, },
removeDocument: function (object: StoredObject): void { removeDocument: function (object: StoredObject): void {
console.log("catch remove document", object); console.log("catch remove document", object);

View File

@@ -23,6 +23,7 @@ const emit =
{ {
stored_object_version: StoredObjectVersionCreated, stored_object_version: StoredObjectVersionCreated,
stored_object: StoredObject, stored_object: StoredObject,
file_name: string,
}, },
) => void ) => void
>(); >();
@@ -114,7 +115,21 @@ const handleFile = async (file: File): Promise<void> => {
persisted: false, persisted: false,
}; };
emit("addDocument", { stored_object, stored_object_version }); const fileName = file.name;
let file_name = "Nouveau document";
const file_name_split = fileName.split(".");
if (file_name_split.length > 1) {
const extension = file_name_split
? file_name_split[file_name_split.length - 1]
: "";
file_name = fileName.replace(extension, "").slice(0, -1);
}
emit("addDocument", {
stored_object,
stored_object_version,
file_name: file_name,
});
uploading.value = false; uploading.value = false;
}; };
</script> </script>

View File

@@ -20,6 +20,7 @@ const emit = defineEmits<{
{ {
stored_object: StoredObject, stored_object: StoredObject,
stored_object_version: StoredObjectVersion, stored_object_version: StoredObjectVersion,
file_name: string,
}, },
): void; ): void;
(e: "removeDocument"): void; (e: "removeDocument"): void;
@@ -42,14 +43,16 @@ const buttonState = computed<"add" | "replace">(() => {
function onAddDocument({ function onAddDocument({
stored_object, stored_object,
stored_object_version, stored_object_version,
file_name,
}: { }: {
stored_object: StoredObject; stored_object: StoredObject;
stored_object_version: StoredObjectVersion; stored_object_version: StoredObjectVersion;
file_name: string;
}): void { }): void {
const message = const message =
buttonState.value === "add" ? "Document ajouté" : "Document remplacé"; buttonState.value === "add" ? "Document ajouté" : "Document remplacé";
$toast.success(message); $toast.success(message);
emit("addDocument", { stored_object_version, stored_object }); emit("addDocument", { stored_object_version, stored_object, file_name });
state.showModal = false; state.showModal = false;
} }

View File

@@ -19,6 +19,7 @@ const emit = defineEmits<{
{ {
stored_object: StoredObject, stored_object: StoredObject,
stored_object_version: StoredObjectVersion, stored_object_version: StoredObjectVersion,
file_name: string,
}, },
): void; ): void;
(e: "removeDocument"): void; (e: "removeDocument"): void;
@@ -53,11 +54,13 @@ const dav_link_href = computed<string | undefined>(() => {
const onAddDocument = ({ const onAddDocument = ({
stored_object, stored_object,
stored_object_version, stored_object_version,
file_name,
}: { }: {
stored_object: StoredObject; stored_object: StoredObject;
stored_object_version: StoredObjectVersion; stored_object_version: StoredObjectVersion;
file_name: string;
}): void => { }): void => {
emit("addDocument", { stored_object, stored_object_version }); emit("addDocument", { stored_object, stored_object_version, file_name });
}; };
const onRemoveDocument = (e: Event): void => { const onRemoveDocument = (e: Event): void => {

View File

@@ -53,7 +53,7 @@ const onRestored = ({
<template> <template>
<template v-if="props.versions.length > 0"> <template v-if="props.versions.length > 0">
<div class="container"> <div class="container">
<template v-for="v in props.versions"> <template v-for="v in props.versions" :key="v.id">
<history-button-list-item <history-button-list-item
:version="v" :version="v"
:can-edit="canEdit" :can-edit="canEdit"

View File

@@ -32,13 +32,17 @@ const onRestore = ({
emit("restoreVersion", { newVersion }); emit("restoreVersion", { newVersion });
}; };
const isKeptBeforeConversion = computed<boolean>(() => const isKeptBeforeConversion = computed<boolean>(() => {
props.version["point-in-times"].reduce( if ("point-in-times" in props.version) {
(accumulator: boolean, pit: StoredObjectPointInTime) => return props.version["point-in-times"].reduce(
accumulator || "keep-before-conversion" === pit.reason, (accumulator: boolean, pit: StoredObjectPointInTime) =>
false, accumulator || "keep-before-conversion" === pit.reason,
), false,
); );
} else {
return false;
}
});
const isRestored = computed<boolean>( const isRestored = computed<boolean>(
() => props.version.version > 0 && null !== props.version["from-restored"], () => props.version.version > 0 && null !== props.version["from-restored"],
@@ -90,11 +94,11 @@ const classes = computed<{
<div class="col-12"> <div class="col-12">
<file-icon :type="version.type"></file-icon> <file-icon :type="version.type"></file-icon>
<span <span
><strong>#{{ version.version + 1 }}</strong></span ><strong>&nbsp;#{{ version.version + 1 }}&nbsp;</strong></span
> >
<template <template
v-if="version.createdBy !== null && version.createdAt !== null" v-if="version.createdBy !== null && version.createdAt !== null"
><strong v-if="version.version == 0">Créé par</strong ><strong v-if="version.version == 0">créé par</strong
><strong v-else>modifié par</strong> ><strong v-else>modifié par</strong>
<span class="badge-user" <span class="badge-user"
><UserRenderBoxBadge ><UserRenderBoxBadge

View File

@@ -20,9 +20,11 @@
{{ mm.mimeIcon(document.object.type) }} {{ mm.mimeIcon(document.object.type) }}
</div> </div>
{% endif %} {% endif %}
<div> {% if document.category %}
<p>{{ document.category.name|localize_translatable_string }}</p> <div>
</div> <p>{{ document.category.name|localize_translatable_string }}</p>
</div>
{% endif %}
{% if document.object.hasTemplate %} {% if document.object.hasTemplate %}
<div> <div>
<p>{{ document.object.template.name|localize_translatable_string }}</p> <p>{{ document.object.template.name|localize_translatable_string }}</p>

View File

@@ -33,6 +33,8 @@
@import './scss/hover.scss'; @import './scss/hover.scss';
@import './scss/comment-editor.scss';
/* /*
* BASE LAYOUT POSITION * BASE LAYOUT POSITION
*/ */

View File

@@ -0,0 +1,39 @@
.comment-container {
margin-top: 1.5rem;
}
.toggle-button {
background-color: white;
font-size: .8rem;
text-decoration: none;
position: absolute;
bottom: -10px;
left: 20px;
padding: 2px 6px;
cursor: pointer;
z-index: 10;
transition: left 0.1s ease-in-out;
}
.rich-editor-active .toggle-button {
bottom: 0;
}
.editor-wrapper textarea {
resize: vertical;
min-height: 100px;
}
.editor-container {
position: relative;
display: flex;
flex-direction: column;
}
.editor-wrapper {
position: relative;
}
.hidden-textarea {
display: none;
}

View File

@@ -8,10 +8,10 @@ import {
Heading, Heading,
Link, Link,
List, List,
} from "ckeditor5"; } from 'ckeditor5';
import coreTranslations from "ckeditor5/translations/fr.js"; import coreTranslations from 'ckeditor5/translations/fr.js';
import "ckeditor5/ckeditor5.css"; import 'ckeditor5/ckeditor5.css';
import "./index.scss"; import "./index.scss";
@@ -41,6 +41,8 @@ export default {
"redo", "redo",
], ],
}, },
translations: [coreTranslations], translations: [
coreTranslations
],
licenseKey: "GPL", licenseKey: "GPL",
}; } ;

View File

@@ -1,12 +1,23 @@
import config from "./editor_config"; import App from "../../vuejs/CommentEditor/App.vue"
import { ClassicEditor } from "ckeditor5"; import { createApp, reactive } from "vue";
const ckeditorFields: NodeListOf<HTMLTextAreaElement> = const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
document.querySelectorAll("textarea[ckeditor]"); document.querySelectorAll("[id^='comment-app']");
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
ClassicEditor.create(field, config).catch((error) => { const globalState = reactive({
console.error(error.stack); isSimple: localStorage.getItem('editorMode') === 'simple'
throw error; });
}); window.addEventListener('storage', () => {
globalState.isSimple = localStorage.getItem('editorMode') === 'simple';
});
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
const app = createApp(App,{
fieldName: field.dataset.fieldName,
template: `<app></app>`
});
app.provide('globalState', globalState)
.component("app", App)
.mount(field);
}); });
//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));

View File

@@ -10,6 +10,10 @@ let appsPerInput = new Map();
function loadDynamicPicker(element) { function loadDynamicPicker(element) {
let apps = element.querySelectorAll('[data-module="pick-dynamic"]'); let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
let suggested;
let as_id;
let submit_on_adding_new_entity;
let label;
apps.forEach(function (el) { apps.forEach(function (el) {
const isMultiple = parseInt(el.dataset.multiple) === 1, const isMultiple = parseInt(el.dataset.multiple) === 1,

View File

@@ -1,45 +0,0 @@
import { createApp } from "vue";
import OpenWopiLink from "ChillMainAssets/vuejs/_components/OpenWopiLink";
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
const i18n = _createI18n({});
//TODO move to chillDocStore or ChillWopi
/*
tags to load module:
<span data-module="wopi-link"
data-wopi-url="{{ path('chill_wopi_file_edit', {'fileId': document.uuid}) }}"
data-doc-type="{{ document.type|e('html_attr') }}"
data-options="{{ options|json_encode }}"
></span>
*/
window.addEventListener("DOMContentLoaded", function (e) {
document
.querySelectorAll('span[data-module="wopi-link"]')
.forEach(function (el) {
createApp({
template:
'<open-wopi-link :wopiUrl="wopiUrl" :type="type" :options="options"></open-wopi-link>',
components: {
OpenWopiLink,
},
data() {
return {
wopiUrl: el.dataset.wopiUrl,
type: el.dataset.docType,
options:
el.dataset.options !== "null"
? JSON.parse(el.dataset.options)
: {},
};
},
})
.use(i18n)
.mount(el);
});
});

View File

@@ -0,0 +1,36 @@
<template>
<div>
<div>
<comment-editor
:isSimple="globalState.isSimple"
:fieldName="fieldName"
@toggle="toggleEditorMode"
></comment-editor>
</div>
</div>
</template>
<script>
import { defineComponent, inject } from 'vue';
import CommentEditor from "../CommentEditor/component/CommentEditor.vue";
export default defineComponent({
name: "App",
components: { CommentEditor },
props: {
fieldName: String
},
setup() {
const globalState = inject('globalState');
const toggleEditorMode = () => {
globalState.isSimple = !globalState.isSimple;
localStorage.setItem('editorMode', globalState.isSimple ? 'simple' : 'rich');
};
return {
globalState,
toggleEditorMode,
};
}
});
</script>

View File

@@ -0,0 +1,58 @@
<template>
<div :class="{'editor-container': true, 'rich-editor-active': !isSimple}">
<div v-if="!isSimple" class="editor-wrapper">
<ckeditor
:name="fieldName"
:editor="classicEditor"
:config="editorConfig"
v-model.lazy="content"
tag-name="textarea"
/>
</div>
<div v-else class="editor-wrapper">
<textarea
v-model.lazy="content"
:name="fieldName"
class="form-control"
></textarea>
</div>
<a @click="toggleSimpleEditor" class="toggle-button">{{ isSimple ? "rich" : "simple" }}</a>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, computed, toRefs } from 'vue';
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { ClassicEditor } from "ckeditor5";
export default defineComponent({
name: "CommentEditor",
components: {
ckeditor: Ckeditor,
},
props: {
type: String,
isSimple: Boolean,
fieldName: String,
},
setup(props, { emit }) {
const { isSimple } = toRefs(props);
const content = ref("");
const classicEditor = ClassicEditor;
const editorConfig = classicEditorConfig;
const toggleSimpleEditor = () => {
emit("toggle");
};
return {
isSimple,
content,
classicEditor,
editorConfig,
toggleSimpleEditor,
};
}
});
</script>

View File

@@ -0,0 +1,14 @@
import {personMessages} from "ChillPersonAssets/vuejs/_js/i18n";
import {calendarUserSelectorMessages} from "ChillCalendarAssets/vuejs/_components/CalendarUserSelector/js/i18n";
import {activityMessages} from "ChillActivityAssets/vuejs/Activity/i18n";
const appMessages = {
fr: {
mode: {
simple: "Editeur simple",
rich: "Editeur riche"
}
},
};
export { appMessages };

View File

@@ -1,214 +0,0 @@
<template>
<a
v-if="isOpenDocument"
class="btn"
:class="[
isChangeIcon ? 'change-icon' : '',
isChangeClass ? options.changeClass : 'btn-wopilink',
]"
@click="openModal"
>
<i v-if="isChangeIcon" class="fa me-2" :class="options.changeIcon"></i>
<span v-if="!noText">
{{ trans(WOPI_ONLINE_EDIT_DOCUMENT) }}
</span>
</a>
<teleport to="body">
<div class="wopi-frame" v-if="isOpenDocument">
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
:hideFooter="true"
@close="modal.showModal = false"
>
<template #header>
<img class="logo" :src="logo" height="45" />
<span class="ms-auto me-3">
<span v-if="options.title">{{ options.title }}</span>
</span>
</template>
<template #body>
<div v-if="loading" class="loading">
<i
class="fa fa-circle-o-notch fa-spin fa-3x"
:title="trans(WOPI_LOADING)"
></i>
</div>
<iframe :src="this.wopiUrl" @load="loaded"></iframe>
</template>
</modal>
</div>
<div v-else>
<Modal
v-if="modal.showModal"
modalDialogClass="modal-sm"
@close="modal.showModal = false"
>
<template v-slot:header>
<h3>{{ trans(WOPI_INVALID_TITLE) }}</h3>
</template>
<template v-slot:body>
<div class="alert alert-warning">
{{ trans(WOPI_ONLINE_EDIT_DOCUMENT) }}
</div>
</template>
</Modal>
</div>
</teleport>
</template>
<script setup>
import { ref, computed } from "vue";
import {
trans,
WOPI_ONLINE_EDIT_DOCUMENT,
WOPI_INVALID_TITLE,
WOPI_LOADING,
} from "translator";
import Modal from "ChillMainAssets/vuejs/_components/Modal";
import logo from "ChillMainAssets/chill/img/logo-chill-sans-slogan_white.png";
// Props
const props = defineProps({
wopiUrl: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
options: {
type: Object,
required: false,
},
});
// data
const modal = ref({
showModal: false,
modalDialogClass: "modal-fullscreen",
});
const loading = ref(false);
// MIME types
const mime = [
// TODO temporary hardcoded. to be replaced by twig extension or a collabora server query
"application/clarisworks",
"application/coreldraw",
"application/macwriteii",
"application/msword",
"application/pdf",
"application/vnd.lotus-1-2-3",
"application/vnd.ms-excel",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12",
"application/vnd.ms-excel.sheet.macroEnabled.12",
"application/vnd.ms-excel.template.macroEnabled.12",
"application/vnd.ms-powerpoint",
"application/vnd.ms-powerpoint.presentation.macroEnabled.12",
"application/vnd.ms-powerpoint.template.macroEnabled.12",
"application/vnd.ms-visio.drawing",
"application/vnd.ms-word.document.macroEnabled.12",
"application/vnd.ms-word.template.macroEnabled.12",
"application/vnd.ms-works",
"application/vnd.oasis.opendocument.chart",
"application/vnd.oasis.opendocument.formula",
"application/vnd.oasis.opendocument.graphics",
"application/vnd.oasis.opendocument.graphics-flat-xml",
"application/vnd.oasis.opendocument.graphics-template",
"application/vnd.oasis.opendocument.presentation",
"application/vnd.oasis.opendocument.presentation-flat-xml",
"application/vnd.oasis.opendocument.presentation-template",
"application/vnd.oasis.opendocument.spreadsheet",
"application/vnd.oasis.opendocument.spreadsheet-flat-xml",
"application/vnd.oasis.opendocument.spreadsheet-template",
"application/vnd.oasis.opendocument.text",
"application/vnd.oasis.opendocument.text-flat-xml",
"application/vnd.oasis.opendocument.text-master",
"application/vnd.oasis.opendocument.text-master-template",
"application/vnd.oasis.opendocument.text-template",
"application/vnd.oasis.opendocument.text-web",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
"application/vnd.openxmlformats-officedocument.presentationml.template",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
"application/vnd.sun.xml.calc",
"application/vnd.sun.xml.calc.template",
"application/vnd.sun.xml.chart",
"application/vnd.sun.xml.draw",
"application/vnd.sun.xml.draw.template",
"application/vnd.sun.xml.impress",
"application/vnd.sun.xml.impress.template",
"application/vnd.sun.xml.math",
"application/vnd.sun.xml.writer",
"application/vnd.sun.xml.writer.global",
"application/vnd.sun.xml.writer.template",
"application/vnd.visio",
"application/vnd.visio2013",
"application/vnd.wordperfect",
"application/x-abiword",
"application/x-aportisdoc",
"application/x-dbase",
"application/x-dif-document",
"application/x-fictionbook+xml",
"application/x-gnumeric",
"application/x-hwp",
"application/x-iwork-keynote-sffkey",
"application/x-iwork-numbers-sffnumbers",
"application/x-iwork-pages-sffpages",
"application/x-mspublisher",
"application/x-mswrite",
"application/x-pagemaker",
"application/x-sony-bbeb",
"application/x-t602",
];
// Computed
const isOpenDocument = computed(() => mime.includes(props.type));
const noText = computed(() => props.options?.noText === true);
const isChangeIcon = computed(() => !!props.options?.changeIcon);
const isChangeClass = computed(() => !!props.options?.changeClass);
// Methods
const openModal = () => {
loading.value = true;
modal.value.showModal = true;
};
const loaded = () => {
loading.value = false;
};
</script>
<style lang="scss">
div.wopi-frame {
div.modal-header {
border-bottom: 0;
background-color: var(--bs-primary);
color: white;
}
div.modal-body {
padding: 0;
overflow-y: unset !important;
iframe {
height: 100%;
width: 100%;
}
div.loading {
position: absolute;
color: var(--bs-chill-gray);
top: calc(50% - 30px);
left: calc(50% - 30px);
}
}
}
</style>

View File

@@ -54,6 +54,11 @@ const messages = {
residential_address: "Adresse de résidence", residential_address: "Adresse de résidence",
located_at: "réside chez", located_at: "réside chez",
}, },
comment: {
label: "Commentaire",
editor_simple: "Simple",
editor_rich: "Riche"
}
}, },
}; };

View File

@@ -214,7 +214,9 @@
{% block private_comment_widget %} {% block private_comment_widget %}
{% for entry in form %} {% for entry in form %}
{{ form_widget(entry) }} <div id="comment-app-{{ form.vars.id }}" data-field-name="{{ form.vars.full_name }}">
{{ form_widget(entry, { attr: { ckeditor: 'true' } }) }}
</div>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
@@ -224,7 +226,9 @@
{% block comment_widget %} {% block comment_widget %}
{% for entry in form %} {% for entry in form %}
{{ form_widget(entry) }} <div id="comment-app-{{ form.vars.id }}" data-field-name="{{ form.vars.full_name }}">
{{ form_widget(entry, { attr: { ckeditor: 'true' } }) }}
</div>
{% endfor %} {% endfor %}
{% endblock comment_widget %} {% endblock comment_widget %}

View File

@@ -9,7 +9,6 @@
{{ encore_entry_script_tags('mod_pickentity_type') }} {{ encore_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_entity_workflow_subscribe') }} {{ encore_entry_script_tags('mod_entity_workflow_subscribe') }}
{{ encore_entry_script_tags('page_workflow_show') }} {{ encore_entry_script_tags('page_workflow_show') }}
{{ encore_entry_script_tags('mod_wopi_link') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }} {{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_workflow_attachment') }} {{ encore_entry_script_tags('mod_workflow_attachment') }}
{% endblock %} {% endblock %}
@@ -19,7 +18,6 @@
{{ encore_entry_link_tags('mod_pickentity_type') }} {{ encore_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('mod_entity_workflow_subscribe') }} {{ encore_entry_link_tags('mod_entity_workflow_subscribe') }}
{{ encore_entry_link_tags('page_workflow_show') }} {{ encore_entry_link_tags('page_workflow_show') }}
{{ encore_entry_link_tags('mod_wopi_link') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }} {{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_workflow_attachment') }} {{ encore_entry_link_tags('mod_workflow_attachment') }}
{% endblock %} {% endblock %}

View File

@@ -86,10 +86,6 @@ module.exports = function (encore, entries) {
"mod_entity_workflow_pick", "mod_entity_workflow_pick",
__dirname + "/Resources/public/module/entity-workflow-pick/index.js", __dirname + "/Resources/public/module/entity-workflow-pick/index.js",
); );
encore.addEntry(
"mod_wopi_link",
__dirname + "/Resources/public/module/wopi-link/index.js",
);
encore.addEntry( encore.addEntry(
"mod_pick_postal_code", "mod_pick_postal_code",
__dirname + "/Resources/public/module/pick-postal-code/index.js", __dirname + "/Resources/public/module/pick-postal-code/index.js",

View File

@@ -59,6 +59,7 @@ user_group:
inactive: Inactif inactive: Inactif
with_users: Membres with_users: Membres
no_users: Aucun utilisateur associé no_users: Aucun utilisateur associé
no_user_groups: Aucune groupe d'utilisateurs
no_admin_users: Aucun administrateur no_admin_users: Aucun administrateur
Label: Nom du groupe Label: Nom du groupe
BackgroundColor: Couleur de fond du badge BackgroundColor: Couleur de fond du badge
@@ -112,6 +113,8 @@ Any comment: Aucun commentaire
# comment embeddable # comment embeddable
No comment associated: Aucun commentaire No comment associated: Aucun commentaire
private comment: Notes privées private comment: Notes privées
comment_public: Note
comment_private: Note privée
#pagination #pagination
Previous: Précédent Previous: Précédent
@@ -739,6 +742,7 @@ export:
id: Identifiant de l'action id: Identifiant de l'action
social_issue_id: Identifiant de la problématique sociale social_issue_id: Identifiant de la problématique sociale
social_issue: Problématique sociale social_issue: Problématique sociale
desactivation_date: Date de désactivation
social_issue_ordering: Ordre de la problématique sociale social_issue_ordering: Ordre de la problématique sociale
action_label: Action d'accompagnement action_label: Action d'accompagnement
action_ordering: Ordre action_ordering: Ordre

View File

@@ -207,7 +207,6 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
$works = $this->workRepository->findByAccompanyingPeriod( $works = $this->workRepository->findByAccompanyingPeriod(
$accompanyingCourse, $accompanyingCourse,
['startDate' => 'DESC', 'endDate' => 'DESC'], ['startDate' => 'DESC', 'endDate' => 'DESC'],
3
); );
$counters = [ $counters = [
@@ -220,7 +219,7 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
'accompanyingCourse' => $accompanyingCourse, 'accompanyingCourse' => $accompanyingCourse,
'withoutHousehold' => $withoutHousehold, 'withoutHousehold' => $withoutHousehold,
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(), 'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
'works' => $works, 'works' => \array_slice($works, 0, 3),
'activities' => \array_slice($activities, 0, 3), 'activities' => \array_slice($activities, 0, 3),
'counters' => $counters, 'counters' => $counters,
]); ]);

View File

@@ -22,7 +22,7 @@ use Doctrine\ORM\Mapping as ORM;
class MaritalStatus class MaritalStatus
{ {
#[ORM\Id] #[ORM\Id]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 7)] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 15)]
private ?string $id; private ?string $id;
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]

View File

@@ -87,7 +87,7 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
], ]) ], ])
->setExtras([ ->setExtras([
'order' => 40, 'order' => 40,
'counter' => count($period->getOpenWorks()) > 0 ? count($period->getOpenWorks()) : null, 'counter' => count($period->getWorks()) > 0 ? count($period->getWorks()) : null,
]); ]);
} }

View File

@@ -61,15 +61,15 @@
</template> </template>
<script> <script>
import { ClassicEditor } from "ckeditor5"; import {ClassicEditor} from "ckeditor5";
import { Ckeditor } from "@ckeditor/ckeditor5-vue"; import {Ckeditor} from "@ckeditor/ckeditor5-vue";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config"; import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { mapState } from "vuex"; import { mapState } from "vuex";
export default { export default {
name: "Comment", name: "Comment",
components: { components: {
ckeditor: Ckeditor, ckeditor: Ckeditor
}, },
data() { data() {
return { return {

View File

@@ -39,15 +39,15 @@
<script> <script>
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue"; import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods"; import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import { Ckeditor } from "@ckeditor/ckeditor5-vue"; import { Ckeditor }from "@ckeditor/ckeditor5-vue";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config"; import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { ClassicEditor } from "ckeditor5"; import {ClassicEditor} from "ckeditor5";
export default { export default {
name: "WriteComment", name: "WriteComment",
components: { components: {
Modal, Modal,
ckeditor: Ckeditor, ckeditor: Ckeditor
}, },
props: ["resource"], props: ["resource"],
emits: ["updateComment"], emits: ["updateComment"],

View File

@@ -46,8 +46,7 @@
<label class="col-form-label">{{ $t("comments") }}</label> <label class="col-form-label">{{ $t("comments") }}</label>
<ckeditor <ckeditor
v-model="note" v-model="note"
:editor="classicEditor" :editor="classicEditor" :config="editorConfig"
:config="editorConfig"
tag-name="textarea" tag-name="textarea"
></ckeditor> ></ckeditor>
</div> </div>
@@ -208,6 +207,29 @@
</label> </label>
</div> </div>
</li> </li>
<li
v-for="p in getPreviousPersons"
:key="p.id"
class="alert alert-danger"
>
<div class="form-check">
<input
v-model="personsPicked"
:value="p.id"
type="checkbox"
class="me-2 form-check-input"
:id="'person_check' + p.id"
/>
<label :for="'person_check' + p.id" class="form-check-label">
<person-text :person="p"></person-text>
</label>
</div>
<span
><i class="fa fa-warning"></i>&nbsp;{{
$t("warning_previous_persons")
}}</span
>
</li>
</ul> </ul>
</div> </div>
@@ -440,7 +462,7 @@
import { mapState, mapGetters } from "vuex"; import { mapState, mapGetters } from "vuex";
import { Ckeditor } from "@ckeditor/ckeditor5-vue"; import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config"; import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { ClassicEditor } from "ckeditor5"; import {ClassicEditor} from "ckeditor5";
import AddResult from "./components/AddResult.vue"; import AddResult from "./components/AddResult.vue";
import AddEvaluation from "./components/AddEvaluation.vue"; import AddEvaluation from "./components/AddEvaluation.vue";
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue"; import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
@@ -497,6 +519,8 @@ const i18n = {
notification_notify_referrer: "Notifier le référent", notification_notify_referrer: "Notifier le référent",
notification_notify_any: "Notifier d'autres utilisateurs", notification_notify_any: "Notifier d'autres utilisateurs",
notification_send: "Envoyer une notification", notification_send: "Envoyer une notification",
warning_previous_persons:
"Cet usager n'est désormais plus concerné par le parcours, bien qu'il ait été associé à l'action par le passé.",
}, },
}, },
}; };
@@ -583,6 +607,7 @@ export default {
"hasHandlingThirdParty", "hasHandlingThirdParty",
"hasThirdParties", "hasThirdParties",
"hasReferrers", "hasReferrers",
"getPreviousPersons",
]), ]),
classicEditor: () => ClassicEditor, classicEditor: () => ClassicEditor,
editorConfig: () => classicEditorConfig, editorConfig: () => classicEditorConfig,

View File

@@ -273,7 +273,7 @@
<script> <script>
import { ISOToDatetime } from "ChillMainAssets/chill/js/date"; import { ISOToDatetime } from "ChillMainAssets/chill/js/date";
import { Ckeditor } from "@ckeditor/ckeditor5-vue"; import {Ckeditor} from "@ckeditor/ckeditor5-vue";
import { ClassicEditor } from "ckeditor5"; import { ClassicEditor } from "ckeditor5";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config"; import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { mapState } from "vuex"; import { mapState } from "vuex";
@@ -535,11 +535,11 @@ export default {
title: title, title: title,
}); });
}, },
addDocument({ stored_object, stored_object_version }) { addDocument({ stored_object, stored_object_version, file_name }) {
let document = { let document = {
type: "accompanying_period_work_evaluation_document", type: "accompanying_period_work_evaluation_document",
storedObject: stored_object, storedObject: stored_object,
title: "Nouveau document", title: file_name,
}; };
this.$store.commit("addDocument", { this.$store.commit("addDocument", {
key: this.evaluation.key, key: this.evaluation.key,

View File

@@ -87,6 +87,11 @@ const store = createStore({
return []; return [];
}, },
getPreviousPersons(state) {
return state.personsPicked.filter(
(p) => !state.personsReachables.map((pr) => pr.id).includes(p.id),
);
},
buildPayload(state) { buildPayload(state) {
return { return {
type: "accompanying_period_work", type: "accompanying_period_work",
@@ -607,8 +612,7 @@ const store = createStore({
submit({ getters, state, commit }, callback) { submit({ getters, state, commit }, callback) {
let payload = getters.buildPayload, let payload = getters.buildPayload,
params = new URLSearchParams({ entity_version: state.version }), params = new URLSearchParams({ entity_version: state.version }),
url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`, url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`;
errors = [];
commit("setIsPosting", true); commit("setIsPosting", true);
// console.log('the social action', payload); // console.log('the social action', payload);

View File

@@ -30,8 +30,7 @@
<div class="item-row comment"> <div class="item-row comment">
<ckeditor <ckeditor
:editor="classicEditor" :editor="classicEditor" :config="editorConfig"
:config="editorConfig"
v-model="comment" v-model="comment"
tag-name="textarea" tag-name="textarea"
/> />
@@ -103,9 +102,9 @@ div.participation-details {
<script> <script>
import { mapGetters } from "vuex"; import { mapGetters } from "vuex";
import PersonRenderBox from "ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue"; import PersonRenderBox from "ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue";
import { Ckeditor } from "@ckeditor/ckeditor5-vue"; import {Ckeditor} from "@ckeditor/ckeditor5-vue";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config"; import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { ClassicEditor } from "ckeditor5"; import {ClassicEditor} from "ckeditor5";
export default { export default {
name: "MemberDetails", name: "MemberDetails",

View File

@@ -1,25 +1,25 @@
<template> <template>
<ckeditor <ckeditor
name="content" name="content"
:placeholder=" :placeholder="
$t('household_members_editor.positioning.comment_placeholder') $t('household_members_editor.positioning.comment_placeholder')
" "
:editor="editor" :editor="editor"
:config="editorConfig" :config="editorConfig"
v-model="content" v-model="content"
tag-name="textarea" tag-name="textarea"
/> />
</template> </template>
<script> <script>
import { Ckeditor } from "@ckeditor/ckeditor5-vue"; import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config"; import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import { ClassicEditor } from "ckeditor5"; import {ClassicEditor} from "ckeditor5";
export default { export default {
name: "PersonComment.vue", name: "PersonComment.vue",
components: { components: {
ckeditor: Ckeditor, ckeditor: Ckeditor
}, },
props: ["conc"], props: ["conc"],
computed: { computed: {

View File

@@ -8,7 +8,7 @@ L'usager {{ oldPersonLocation|chill_entity_render_string }} a déménagé.
Son adresse était utilisée pour localiser le parcours n°{{ period.id }}, dont vous êtes Son adresse était utilisée pour localiser le parcours n°{{ period.id }}, dont vous êtes
le référent. le référent.
En conséquence de ce déménage, le parcours est toujours localisé à cette adresse, mais à l'aide d'une En conséquence de ce déménagement, le parcours est toujours localisé à cette adresse, mais à l'aide d'une
adresse temporaire. adresse temporaire.
Si vous continuez à suivre le parcours, vous pouvez le localiser à nouveau auprès de l'adresse de Si vous continuez à suivre le parcours, vous pouvez le localiser à nouveau auprès de l'adresse de

View File

@@ -30,9 +30,6 @@ final readonly class SocialActionCSVExportService
private TranslatorInterface $translator, private TranslatorInterface $translator,
) {} ) {}
/**
* @param list<SocialAction> $actions
*/
public function generateCsv(array $actions): Writer public function generateCsv(array $actions): Writer
{ {
// CSV headers // CSV headers
@@ -84,7 +81,8 @@ final readonly class SocialActionCSVExportService
'action_id' => $action->getId(), 'action_id' => $action->getId(),
'social_issue_id' => $action->getIssue()?->getId(), 'social_issue_id' => $action->getIssue()?->getId(),
'problematique_label' => null !== $action->getIssue() ? $this->socialIssueRender->renderString($action->getIssue(), []) : null, 'problematique_label' => null !== $action->getIssue() ? $this->socialIssueRender->renderString($action->getIssue(), []) : null,
'social_issue_ordering' => null !== $action->getIssue() ? $action->getIssue()->getOrdering() : null, 'desactivation_date' => $action->getDesactivationDate()?->format('Y-m-d'),
'social_issue_ordering' => $action->getIssue()?->getOrdering(),
'action_label' => $this->socialActionRender->renderString($action, []), 'action_label' => $this->socialActionRender->renderString($action, []),
'action_ordering' => $action->getOrdering(), 'action_ordering' => $action->getOrdering(),
'goal_label' => null !== $goal ? $this->stringHelper->localize($goal->getTitle()) : null, 'goal_label' => null !== $goal ? $this->stringHelper->localize($goal->getTitle()) : null,

View File

@@ -44,6 +44,7 @@ readonly class SocialIssueCSVExportService
'Id', 'Id',
'Label', 'Label',
'Social issue', 'Social issue',
'export.social_action_list.desactivation_date',
'socialIssue.isParent?', 'socialIssue.isParent?',
'socialIssue.Parent id', 'socialIssue.Parent id',
] ]
@@ -66,6 +67,7 @@ readonly class SocialIssueCSVExportService
'id' => $issue->getId(), 'id' => $issue->getId(),
'label' => $this->stringHelper->localize($issue->getTitle()), 'label' => $this->stringHelper->localize($issue->getTitle()),
'title' => $this->socialIssueRender->renderString($issue, []), 'title' => $this->socialIssueRender->renderString($issue, []),
'export.social_action_list.desactivation_date' => $issue->getDesactivationDate()?->format('Y-m-d'),
'isParent' => $issue->hasChildren() ? 'X' : '', 'isParent' => $issue->hasChildren() ? 'X' : '',
'parent_id' => null !== $issue->getParent() ? $issue->getParent()->getId() : '', 'parent_id' => null !== $issue->getParent() ? $issue->getParent()->getId() : '',
]; ];

View File

@@ -52,6 +52,7 @@ class SocialActionCsvExporterTest extends TestCase
// Création d'une instance réelle de SocialAction sans objectifs ni résultats // Création d'une instance réelle de SocialAction sans objectifs ni résultats
$actionWithoutGoalsOrResults = new SocialAction(); $actionWithoutGoalsOrResults = new SocialAction();
$actionWithoutGoalsOrResults->setIssue($socialIssue); $actionWithoutGoalsOrResults->setIssue($socialIssue);
$actionWithoutGoalsOrResults->setDesactivationDate(new \DateTime('2025-05-21'));
$actionWithoutGoalsOrResults->setTitle(['fr' => 'Action without goals or results']); $actionWithoutGoalsOrResults->setTitle(['fr' => 'Action without goals or results']);
// Création d'une instance réelle de SocialAction avec des objectifs et des résultats // Création d'une instance réelle de SocialAction avec des objectifs et des résultats
@@ -61,6 +62,7 @@ class SocialActionCsvExporterTest extends TestCase
$actionWithGoalsAndResults = new SocialAction(); $actionWithGoalsAndResults = new SocialAction();
$actionWithGoalsAndResults->setIssue($socialIssue); $actionWithGoalsAndResults->setIssue($socialIssue);
$actionWithGoalsAndResults->setDesactivationDate(new \DateTime('2025-05-21'));
$actionWithGoalsAndResults->setTitle(['fr' => 'Action with goals and results']); $actionWithGoalsAndResults->setTitle(['fr' => 'Action with goals and results']);
$actionWithGoalsAndResults->addGoal($goalWithResult); $actionWithGoalsAndResults->addGoal($goalWithResult);
@@ -68,6 +70,7 @@ class SocialActionCsvExporterTest extends TestCase
$goalWithoutResult = new Goal(); $goalWithoutResult = new Goal();
$actionWithGoalsNoResults = new SocialAction(); $actionWithGoalsNoResults = new SocialAction();
$actionWithGoalsNoResults->setIssue($socialIssue); $actionWithGoalsNoResults->setIssue($socialIssue);
$actionWithGoalsNoResults->setDesactivationDate(new \DateTime('2025-05-21'));
$actionWithGoalsNoResults->setTitle(['fr' => 'Action with goals and no results']); $actionWithGoalsNoResults->setTitle(['fr' => 'Action with goals and no results']);
$actionWithGoalsNoResults->addGoal($goalWithoutResult); $actionWithGoalsNoResults->addGoal($goalWithoutResult);
@@ -76,6 +79,7 @@ class SocialActionCsvExporterTest extends TestCase
$resultWithNoAction->setTitle(['fr' => 'Result without objectives']); $resultWithNoAction->setTitle(['fr' => 'Result without objectives']);
$actionWithResultsNoGoals = new SocialAction(); $actionWithResultsNoGoals = new SocialAction();
$actionWithResultsNoGoals->setIssue($socialIssue); $actionWithResultsNoGoals->setIssue($socialIssue);
$actionWithResultsNoGoals->setDesactivationDate(new \DateTime('2025-05-21'));
$actionWithResultsNoGoals->setTitle(['fr' => 'Action with results and no goals']); $actionWithResultsNoGoals->setTitle(['fr' => 'Action with results and no goals']);
$actionWithResultsNoGoals->addResult($resultWithNoAction); $actionWithResultsNoGoals->addResult($resultWithNoAction);
@@ -91,11 +95,11 @@ class SocialActionCsvExporterTest extends TestCase
$this->assertStringContainsString('Action with results and no goals', $content); $this->assertStringContainsString('Action with results and no goals', $content);
self::assertEquals(<<<'CSV' self::assertEquals(<<<'CSV'
export.social_action_list.action_id,export.social_action_list.social_issue_id,export.social_action_list.problematique_label,export.social_action_list.social_issue_ordering,export.social_action_list.action_label,export.social_action_list.action_ordering,export.social_action_list.goal_label,export.social_action_list.goal_id,export.social_action_list.goal_result_label,export.social_action_list.goal_result_id,export.social_action_list.result_without_goal_label,export.social_action_list.result_without_goal_id,export.social_action_list.evaluation_title,export.social_action_list.evaluation_id,export.social_action_list.evaluation_url,export.social_action_list.evaluation_delay_month,export.social_action_list.evaluation_delay_week,export.social_action_list.evaluation_delay_day export.social_action_list.action_id,export.social_action_list.social_issue_id,export.social_action_list.problematique_label,export.social_action_list.desactivation_date,export.social_action_list.social_issue_ordering,export.social_action_list.action_label,export.social_action_list.action_ordering,export.social_action_list.goal_label,export.social_action_list.goal_id,export.social_action_list.goal_result_label,export.social_action_list.goal_result_id,export.social_action_list.result_without_goal_label,export.social_action_list.result_without_goal_id,export.social_action_list.evaluation_title,export.social_action_list.evaluation_id,export.social_action_list.evaluation_url,export.social_action_list.evaluation_delay_month,export.social_action_list.evaluation_delay_week,export.social_action_list.evaluation_delay_day
,,"Issue Title",0,"Action with goals and results",0,"not found",,"not found",,,,,,,,, ,,"Issue Title",2025-05-21,0,"Action with goals and results",0,"not found",,"not found",,,,,,,,,
,,"Issue Title",0,"Action without goals or results",0,,,,,,,,,,,, ,,"Issue Title",2025-05-21,0,"Action without goals or results",0,,,,,,,,,,,,
,,"Issue Title",0,"Action with goals and no results",0,"not found",,,,,,,,,,, ,,"Issue Title",2025-05-21,0,"Action with goals and no results",0,"not found",,,,,,,,,,,
,,"Issue Title",0,"Action with results and no goals",0,,,,,"Result without objectives",,,,,,, ,,"Issue Title",2025-05-21,0,"Action with results and no goals",0,,,,,"Result without objectives",,,,,,,
CSV, $content); CSV, $content);
} }

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\Person;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20250514115009 extends AbstractMigration
{
public function getDescription(): string
{
return 'Allow more characters for maritalstatus id';
}
public function up(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE chill_person_marital_status ALTER id TYPE VARCHAR(15)
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE chill_person_person ALTER maritalstatus_id TYPE VARCHAR(15)
SQL);
}
public function down(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE chill_person_person ALTER maritalStatus_id TYPE VARCHAR(7)
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE chill_person_marital_status ALTER id TYPE VARCHAR(7)
SQL);
}
}

View File

@@ -624,7 +624,7 @@ final class SingleTaskController extends AbstractController
->addCheckbox('status', $statuses, $statuses, $statusTrans); ->addCheckbox('status', $statuses, $statuses, $statusTrans);
$states = $this->singleTaskStateRepository->findAllExistingStates(); $states = $this->singleTaskStateRepository->findAllExistingStates();
$checked = array_values(array_filter($states, fn (string $state) => !in_array($state, ['closed', 'canceled', 'validated'], true))); $checked = array_values(array_filter($states, fn (string $state) => !in_array($state, ['in_progress', 'closed', 'canceled', 'validated'], true)));
if ([] !== $states) { if ([] !== $states) {
$filterBuilder $filterBuilder