Apply prettier to files

This commit is contained in:
Julie Lenaerts 2024-12-11 10:49:11 +01:00
parent a6aa2a81c2
commit ebfd48e41f
31 changed files with 4889 additions and 3883 deletions

View File

@ -1,92 +1,137 @@
<template>
<div v-if="isButtonGroupDisplayable" class="btn-group">
<button :class="Object.assign({'btn': true, 'btn-outline-primary': true, 'dropdown-toggle': true, 'btn-sm': props.small})" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Actions
</button>
<ul class="dropdown-menu">
<li v-if="isEditableOnline">
<wopi-edit-button :stored-object="props.storedObject" :classes="{'dropdown-item': true}" :execute-before-leave="props.executeBeforeLeave"></wopi-edit-button>
</li>
<li v-if="isEditableOnDesktop">
<desktop-edit-button :classes="{'dropdown-item': true}" :edit-link="props.davLink" :expiration-link="props.davLinkExpiration"></desktop-edit-button>
</li>
<li v-if="isConvertibleToPdf">
<convert-button :stored-object="props.storedObject" :filename="filename" :classes="{'dropdown-item': true}"></convert-button>
</li>
<li v-if="isDownloadable">
<download-button :stored-object="props.storedObject" :at-version="props.storedObject.currentVersion" :filename="filename" :classes="{'dropdown-item': true}" :display-action-string-in-button="true"></download-button>
</li>
<li v-if="isHistoryViewable">
<history-button :stored-object="props.storedObject" :can-edit="canEdit && props.storedObject._permissions.canEdit"></history-button>
</li>
</ul>
</div>
<div v-else-if="'pending' === props.storedObject.status">
<div class="btn btn-outline-info">Génération en cours</div>
</div>
<div v-else-if="'failure' === props.storedObject.status">
<div class="btn btn-outline-danger">La génération a échoué</div>
</div>
<div v-if="isButtonGroupDisplayable" class="btn-group">
<button
:class="
Object.assign({
btn: true,
'btn-outline-primary': true,
'dropdown-toggle': true,
'btn-sm': props.small,
})
"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
Actions
</button>
<ul class="dropdown-menu">
<li v-if="isEditableOnline">
<wopi-edit-button
:stored-object="props.storedObject"
:classes="{ 'dropdown-item': true }"
:execute-before-leave="props.executeBeforeLeave"
></wopi-edit-button>
</li>
<li v-if="isEditableOnDesktop">
<desktop-edit-button
:classes="{ 'dropdown-item': true }"
:edit-link="props.davLink"
:expiration-link="props.davLinkExpiration"
></desktop-edit-button>
</li>
<li v-if="isConvertibleToPdf">
<convert-button
:stored-object="props.storedObject"
:filename="filename"
:classes="{ 'dropdown-item': true }"
></convert-button>
</li>
<li v-if="isDownloadable">
<download-button
:stored-object="props.storedObject"
:at-version="props.storedObject.currentVersion"
:filename="filename"
:classes="{ 'dropdown-item': true }"
:display-action-string-in-button="true"
></download-button>
</li>
<li v-if="isHistoryViewable">
<history-button
:stored-object="props.storedObject"
:can-edit="
canEdit && props.storedObject._permissions.canEdit
"
></history-button>
</li>
</ul>
</div>
<div v-else-if="'pending' === props.storedObject.status">
<div class="btn btn-outline-info">Génération en cours</div>
</div>
<div v-else-if="'failure' === props.storedObject.status">
<div class="btn btn-outline-danger">La génération a échoué</div>
</div>
</template>
<script lang="ts" setup>
import {computed, onMounted} from "vue";
import { computed, onMounted } from "vue";
import ConvertButton from "./StoredObjectButton/ConvertButton.vue";
import DownloadButton from "./StoredObjectButton/DownloadButton.vue";
import WopiEditButton from "./StoredObjectButton/WopiEditButton.vue";
import {is_extension_editable, is_extension_viewable, is_object_ready} from "./StoredObjectButton/helpers";
import {
is_extension_editable,
is_extension_viewable,
is_object_ready,
} from "./StoredObjectButton/helpers";
import {
StoredObject,
StoredObjectStatusChange, StoredObjectVersion,
WopiEditButtonExecutableBeforeLeaveFunction
StoredObjectStatusChange,
StoredObjectVersion,
WopiEditButtonExecutableBeforeLeaveFunction,
} from "../types";
import DesktopEditButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DesktopEditButton.vue";
import HistoryButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton.vue";
interface DocumentActionButtonsGroupConfig {
storedObject: StoredObject,
small?: boolean,
canEdit?: boolean,
canDownload?: boolean,
canConvertPdf?: boolean,
returnPath?: string,
storedObject: StoredObject;
small?: boolean;
canEdit?: boolean;
canDownload?: boolean;
canConvertPdf?: boolean;
returnPath?: string;
/**
* Will be the filename displayed to the user when he·she download the document
* (the document will be saved on his disk with this name)
*
* If not set, 'document' will be used.
*/
filename?: string,
/**
* Will be the filename displayed to the user when he·she download the document
* (the document will be saved on his disk with this name)
*
* If not set, 'document' will be used.
*/
filename?: string;
/**
* If set, will execute this function before leaving to the editor
*/
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction,
/**
* If set, will execute this function before leaving to the editor
*/
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction;
/**
* a link to download and edit file using webdav
*/
davLink?: string,
/**
* a link to download and edit file using webdav
*/
davLink?: string;
/**
* the expiration date of the download, as a unix timestamp
*/
davLinkExpiration?: number,
/**
* the expiration date of the download, as a unix timestamp
*/
davLinkExpiration?: number;
}
const emit = defineEmits<{
(e: 'onStoredObjectStatusChange', newStatus: StoredObjectStatusChange): void
}>();
const emit =
defineEmits<
(
e: "onStoredObjectStatusChange",
newStatus: StoredObjectStatusChange,
) => void
>();
const props = withDefaults(defineProps<DocumentActionButtonsGroupConfig>(), {
small: false,
canEdit: true,
canDownload: true,
canConvertPdf: true,
returnPath: window.location.pathname + window.location.search + window.location.hash
small: false,
canEdit: true,
canDownload: true,
canConvertPdf: true,
returnPath:
window.location.pathname +
window.location.search +
window.location.hash,
});
/**
@ -100,22 +145,32 @@ let tryiesForReady = 0;
const maxTryiesForReady = 120;
const isButtonGroupDisplayable = computed<boolean>(() => {
return isDownloadable.value || isEditableOnline.value || isEditableOnDesktop.value || isConvertibleToPdf.value;
return (
isDownloadable.value ||
isEditableOnline.value ||
isEditableOnDesktop.value ||
isConvertibleToPdf.value
);
});
const isDownloadable = computed<boolean>(() => {
return props.storedObject.status === 'ready'
return (
props.storedObject.status === "ready" ||
// happens when the stored object version is just added, but not persisted
|| (props.storedObject.currentVersion !== null && props.storedObject.status === 'empty')
(props.storedObject.currentVersion !== null &&
props.storedObject.status === "empty")
);
});
const isEditableOnline = computed<boolean>(() => {
return props.storedObject.status === 'ready'
&& props.storedObject._permissions.canEdit
&& props.canEdit
&& props.storedObject.currentVersion !== null
&& is_extension_editable(props.storedObject.currentVersion.type)
&& props.storedObject.currentVersion.persisted !== false;
return (
props.storedObject.status === "ready" &&
props.storedObject._permissions.canEdit &&
props.canEdit &&
props.storedObject.currentVersion !== null &&
is_extension_editable(props.storedObject.currentVersion.type) &&
props.storedObject.currentVersion.persisted !== false
);
});
const isEditableOnDesktop = computed<boolean>(() => {
@ -123,62 +178,61 @@ const isEditableOnDesktop = computed<boolean>(() => {
});
const isConvertibleToPdf = computed<boolean>(() => {
return props.storedObject.status === 'ready'
&& props.storedObject._permissions.canSee
&& props.canConvertPdf
&& props.storedObject.currentVersion !== null
&& is_extension_viewable(props.storedObject.currentVersion.type)
&& props.storedObject.currentVersion.type !== 'application/pdf'
&& props.storedObject.currentVersion.persisted !== false;
return (
props.storedObject.status === "ready" &&
props.storedObject._permissions.canSee &&
props.canConvertPdf &&
props.storedObject.currentVersion !== null &&
is_extension_viewable(props.storedObject.currentVersion.type) &&
props.storedObject.currentVersion.type !== "application/pdf" &&
props.storedObject.currentVersion.persisted !== false
);
});
const isHistoryViewable = computed<boolean>(() => {
return props.storedObject.status === 'ready';
return props.storedObject.status === "ready";
});
const checkForReady = function(): void {
if (
'ready' === props.storedObject.status
|| 'empty' === props.storedObject.status
|| 'failure' === props.storedObject.status
// stop reloading if the page stays opened for a long time
|| tryiesForReady > maxTryiesForReady
) {
return;
}
const checkForReady = function (): void {
if (
"ready" === props.storedObject.status ||
"empty" === props.storedObject.status ||
"failure" === props.storedObject.status ||
// stop reloading if the page stays opened for a long time
tryiesForReady > maxTryiesForReady
) {
return;
}
tryiesForReady = tryiesForReady + 1;
tryiesForReady = tryiesForReady + 1;
setTimeout(onObjectNewStatusCallback, 5000);
setTimeout(onObjectNewStatusCallback, 5000);
};
const onObjectNewStatusCallback = async function(): Promise<void> {
const onObjectNewStatusCallback = async function (): Promise<void> {
if (props.storedObject.status === "stored_object_created") {
return Promise.resolve();
}
const new_status = await is_object_ready(props.storedObject);
if (props.storedObject.status !== new_status.status) {
emit("onStoredObjectStatusChange", new_status);
return Promise.resolve();
} else if ("failure" === new_status.status) {
return Promise.resolve();
}
if ("ready" !== new_status.status) {
// we check for new status, unless it is ready
checkForReady();
}
if (props.storedObject.status === 'stored_object_created') {
return Promise.resolve();
}
const new_status = await is_object_ready(props.storedObject);
if (props.storedObject.status !== new_status.status) {
emit('onStoredObjectStatusChange', new_status);
return Promise.resolve();
} else if ('failure' === new_status.status) {
return Promise.resolve();
}
if ('ready' !== new_status.status) {
// we check for new status, unless it is ready
checkForReady();
}
return Promise.resolve();
};
onMounted(() => {
checkForReady();
})
checkForReady();
});
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -1,23 +1,35 @@
<script setup lang="ts">
import {StoredObject, StoredObjectVersionCreated} from "../../types";
import {encryptFile, fetchNewStoredObject, uploadVersion} from "../../js/async-upload/uploader";
import {computed, ref, Ref} from "vue";
import { StoredObject, StoredObjectVersionCreated } from "../../types";
import {
encryptFile,
fetchNewStoredObject,
uploadVersion,
} from "../../js/async-upload/uploader";
import { computed, ref, Ref } from "vue";
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
interface DropFileConfig {
existingDoc?: StoredObject,
existingDoc?: StoredObject;
}
const props = withDefaults(defineProps<DropFileConfig>(), {existingDoc: null});
const props = withDefaults(defineProps<DropFileConfig>(), {
existingDoc: null,
});
const emit = defineEmits<{
(e: 'addDocument', {stored_object_version: StoredObjectVersionCreated, stored_object: StoredObject}): void,
}>();
const emit =
defineEmits<
(
e: "addDocument",
{
stored_object_version: StoredObjectVersionCreated,
stored_object: StoredObject,
},
) => void
>();
const is_dragging: Ref<boolean> = ref(false);
const uploading: Ref<boolean> = ref(false);
const display_filename: Ref<string|null> = ref(null);
const display_filename: Ref<string | null> = ref(null);
const has_existing_doc = computed<boolean>(() => {
return props.existingDoc !== undefined && props.existingDoc !== null;
@ -27,13 +39,13 @@ const onDragOver = (e: Event) => {
e.preventDefault();
is_dragging.value = true;
}
};
const onDragLeave = (e: Event) => {
e.preventDefault();
is_dragging.value = false;
}
};
const onDrop = (e: DragEvent) => {
e.preventDefault();
@ -49,8 +61,8 @@ const onDrop = (e: DragEvent) => {
return;
}
handleFile(files[0])
}
handleFile(files[0]);
};
const onZoneClick = (e: Event) => {
e.stopPropagation();
@ -61,21 +73,21 @@ const onZoneClick = (e: Event) => {
input.addEventListener("change", onFileChange);
input.click();
}
};
const onFileChange = async (event: Event): Promise<void> => {
const input = event.target as HTMLInputElement;
if (input.files && input.files[0]) {
console.log('file added', input.files[0]);
console.log("file added", input.files[0]);
const file = input.files[0];
await handleFile(file);
return Promise.resolve();
}
throw 'No file given';
}
throw "No file given";
};
const handleFile = async (file: File): Promise<void> => {
uploading.value = true;
@ -100,25 +112,39 @@ const handleFile = async (file: File): Promise<void> => {
keyInfos: jsonWebKey,
type: type,
persisted: false,
}
};
emit('addDocument', {stored_object, stored_object_version});
emit("addDocument", { stored_object, stored_object_version });
uploading.value = false;
}
};
</script>
<template>
<div class="drop-file">
<div v-if="!uploading" :class="{ area: true, dragging: is_dragging}" @click="onZoneClick" @dragover="onDragOver" @dragleave="onDragLeave" @drop="onDrop">
<div
v-if="!uploading"
:class="{ area: true, dragging: is_dragging }"
@click="onZoneClick"
@dragover="onDragOver"
@dragleave="onDragLeave"
@drop="onDrop"
>
<p v-if="has_existing_doc" class="file-icon">
<file-icon :type="props.existingDoc?.type"></file-icon>
</p>
<p v-if="display_filename !== null" class="display-filename">{{ display_filename }}</p>
<p v-if="display_filename !== null" class="display-filename">
{{ display_filename }}
</p>
<!-- todo i18n -->
<p v-if="has_existing_doc">Déposez un document ou cliquez ici pour remplacer le document existant</p>
<p v-else>Déposez un document ou cliquez ici pour ouvrir le navigateur de fichier</p>
<p v-if="has_existing_doc">
Déposez un document ou cliquez ici pour remplacer le document
existant
</p>
<p v-else>
Déposez un document ou cliquez ici pour ouvrir le navigateur de
fichier
</p>
</div>
<div v-else class="waiting">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
@ -140,7 +166,8 @@ const handleFile = async (file: File): Promise<void> => {
font-weight: 200;
}
& > .area, & > .waiting {
& > .area,
& > .waiting {
width: 100%;
height: 10rem;
@ -163,5 +190,4 @@ const handleFile = async (file: File): Promise<void> => {
}
}
}
</style>

View File

@ -1,14 +1,13 @@
<script setup lang="ts">
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import {StoredObject, StoredObjectVersion} from "../../types";
import { StoredObject, StoredObjectVersion } from "../../types";
import DropFileWidget from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFileWidget.vue";
import {computed, reactive} from "vue";
import {useToast} from 'vue-toast-notification';
import { computed, reactive } from "vue";
import { useToast } from "vue-toast-notification";
interface DropFileConfig {
allowRemove: boolean,
existingDoc?: StoredObject,
allowRemove: boolean;
existingDoc?: StoredObject;
}
const props = withDefaults(defineProps<DropFileConfig>(), {
@ -16,33 +15,46 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
});
const emit = defineEmits<{
(e: 'addDocument', {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void,
(e: 'removeDocument'): void
(
e: "addDocument",
{
stored_object: StoredObject,
stored_object_version: StoredObjectVersion,
},
): void;
(e: "removeDocument"): void;
}>();
const $toast = useToast();
const state = reactive({showModal: false});
const state = reactive({ showModal: false });
const modalClasses = {"modal-dialog-centered": true, "modal-md": true};
const modalClasses = { "modal-dialog-centered": true, "modal-md": true };
const buttonState = computed<'add'|'replace'>(() => {
const buttonState = computed<"add" | "replace">(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return 'add';
return "add";
}
return 'replace';
})
return "replace";
});
function onAddDocument({stored_object, stored_object_version}: {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void {
const message = buttonState.value === 'add' ? "Document ajouté" : "Document remplacé";
function onAddDocument({
stored_object,
stored_object_version,
}: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
}): void {
const message =
buttonState.value === "add" ? "Document ajouté" : "Document remplacé";
$toast.success(message);
emit('addDocument', {stored_object_version, stored_object});
emit("addDocument", { stored_object_version, stored_object });
state.showModal = false;
}
function onRemoveDocument(): void {
emit('removeDocument');
emit("removeDocument");
}
function openModal(): void {
@ -55,15 +67,30 @@ function closeModal(): void {
</script>
<template>
<button v-if="buttonState === 'add'" @click="openModal" class="btn btn-create">Ajouter un document</button>
<button v-else @click="openModal" class="btn btn-edit">Remplacer le document</button>
<modal v-if="state.showModal" :modal-dialog-class="modalClasses" @close="closeModal">
<button
v-if="buttonState === 'add'"
@click="openModal"
class="btn btn-create"
>
Ajouter un document
</button>
<button v-else @click="openModal" class="btn btn-edit">
Remplacer le document
</button>
<modal
v-if="state.showModal"
:modal-dialog-class="modalClasses"
@close="closeModal"
>
<template v-slot:body>
<drop-file-widget :existing-doc="existingDoc" :allow-remove="allowRemove" @add-document="onAddDocument" @remove-document="onRemoveDocument" ></drop-file-widget>
<drop-file-widget
:existing-doc="existingDoc"
:allow-remove="allowRemove"
@add-document="onAddDocument"
@remove-document="onRemoveDocument"
></drop-file-widget>
</template>
</modal>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,13 +1,12 @@
<script setup lang="ts">
import {StoredObject, StoredObjectVersion} from "../../types";
import {computed, ref, Ref} from "vue";
import { StoredObject, StoredObjectVersion } from "../../types";
import { computed, ref, Ref } from "vue";
import DropFile from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFile.vue";
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
interface DropFileConfig {
allowRemove: boolean,
existingDoc?: StoredObject,
allowRemove: boolean;
existingDoc?: StoredObject;
}
const props = withDefaults(defineProps<DropFileConfig>(), {
@ -15,51 +14,65 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
});
const emit = defineEmits<{
(e: 'addDocument', {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void,
(e: 'removeDocument'): void
(
e: "addDocument",
{
stored_object: StoredObject,
stored_object_version: StoredObjectVersion,
},
): void;
(e: "removeDocument"): void;
}>();
const has_existing_doc = computed<boolean>(() => {
return props.existingDoc !== undefined && props.existingDoc !== null;
});
const dav_link_expiration = computed<number|undefined>(() => {
const dav_link_expiration = computed<number | undefined>(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return undefined;
}
if (props.existingDoc.status !== 'ready') {
if (props.existingDoc.status !== "ready") {
return undefined;
}
return props.existingDoc._links?.dav_link?.expiration;
});
const dav_link_href = computed<string|undefined>(() => {
const dav_link_href = computed<string | undefined>(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return undefined;
}
if (props.existingDoc.status !== 'ready') {
if (props.existingDoc.status !== "ready") {
return undefined;
}
return props.existingDoc._links?.dav_link?.href;
})
});
const onAddDocument = ({stored_object, stored_object_version}: {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void => {
emit('addDocument', {stored_object, stored_object_version});
}
const onAddDocument = ({
stored_object,
stored_object_version,
}: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
}): void => {
emit("addDocument", { stored_object, stored_object_version });
};
const onRemoveDocument = (e: Event): void => {
e.stopPropagation();
e.preventDefault();
emit('removeDocument');
}
emit("removeDocument");
};
</script>
<template>
<div>
<drop-file :existingDoc="props.existingDoc" @addDocument="onAddDocument"></drop-file>
<drop-file
:existingDoc="props.existingDoc"
@addDocument="onAddDocument"
></drop-file>
<ul class="record_actions">
<li v-if="has_existing_doc">
@ -72,12 +85,14 @@ const onRemoveDocument = (e: Event): void => {
/>
</li>
<li>
<button v-if="allowRemove" class="btn btn-delete" @click="onRemoveDocument($event)" ></button>
<button
v-if="allowRemove"
class="btn btn-delete"
@click="onRemoveDocument($event)"
></button>
</li>
</ul>
</div>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -4,22 +4,43 @@ interface FileIconConfig {
}
const props = defineProps<FileIconConfig>();
</script>
<template>
<i class="fa fa-file-pdf-o" v-if="props.type === 'application/pdf'"></i>
<i class="fa fa-file-word-o" v-else-if="props.type === 'application/vnd.oasis.opendocument.text'"></i>
<i class="fa fa-file-word-o" v-else-if="props.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'"></i>
<i class="fa fa-file-word-o" v-else-if="props.type === 'application/msword'"></i>
<i class="fa fa-file-excel-o" v-else-if="props.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"></i>
<i class="fa fa-file-excel-o" v-else-if="props.type === 'application/vnd.ms-excel'"></i>
<i
class="fa fa-file-word-o"
v-else-if="props.type === 'application/vnd.oasis.opendocument.text'"
></i>
<i
class="fa fa-file-word-o"
v-else-if="
props.type ===
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
"
></i>
<i
class="fa fa-file-word-o"
v-else-if="props.type === 'application/msword'"
></i>
<i
class="fa fa-file-excel-o"
v-else-if="
props.type ===
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
"
></i>
<i
class="fa fa-file-excel-o"
v-else-if="props.type === 'application/vnd.ms-excel'"
></i>
<i class="fa fa-file-image-o" v-else-if="props.type === 'image/jpeg'"></i>
<i class="fa fa-file-image-o" v-else-if="props.type === 'image/png'"></i>
<i class="fa fa-file-archive-o" v-else-if="props.type === 'application/x-zip-compressed'"></i>
<i class="fa fa-file-code-o" v-else ></i>
<i
class="fa fa-file-archive-o"
v-else-if="props.type === 'application/x-zip-compressed'"
></i>
<i class="fa fa-file-code-o" v-else></i>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,61 +1,65 @@
<template>
<a :class="props.classes" @click="download_and_open($event)" ref="btn">
<i class="fa fa-file-pdf-o"></i>
Télécharger en pdf
</a>
<a :class="props.classes" @click="download_and_open($event)" ref="btn">
<i class="fa fa-file-pdf-o"></i>
Télécharger en pdf
</a>
</template>
<script lang="ts" setup>
import {build_convert_link, download_and_decrypt_doc, download_doc} from "./helpers";
import {
build_convert_link,
download_and_decrypt_doc,
download_doc,
} from "./helpers";
import mime from "mime";
import {reactive, ref} from "vue";
import {StoredObject} from "../../types";
import { reactive, ref } from "vue";
import { StoredObject } from "../../types";
interface ConvertButtonConfig {
storedObject: StoredObject,
classes: { [key: string]: boolean},
filename?: string,
};
storedObject: StoredObject;
classes: Record<string, boolean>;
filename?: string;
}
interface DownloadButtonState {
content: null|string
content: null | string;
}
const props = defineProps<ConvertButtonConfig>();
const state: DownloadButtonState = reactive({content: null});
const state: DownloadButtonState = reactive({ content: null });
const btn = ref<HTMLAnchorElement | null>(null);
async function download_and_open(event: Event): Promise<void> {
const button = event.target as HTMLAnchorElement;
const button = event.target as HTMLAnchorElement;
if (null === state.content) {
event.preventDefault();
if (null === state.content) {
event.preventDefault();
const raw = await download_doc(build_convert_link(props.storedObject.uuid));
state.content = window.URL.createObjectURL(raw);
const raw = await download_doc(
build_convert_link(props.storedObject.uuid),
);
state.content = window.URL.createObjectURL(raw);
button.href = window.URL.createObjectURL(raw);
button.type = 'application/pdf';
button.href = window.URL.createObjectURL(raw);
button.type = "application/pdf";
button.download = (props.filename + '.pdf') || 'document.pdf';
}
button.download = props.filename + ".pdf" || "document.pdf";
}
button.click();
const reset_pending = setTimeout(reset_state, 45000);
button.click();
const reset_pending = setTimeout(reset_state, 45000);
}
function reset_state(): void {
state.content = null;
btn.value?.removeAttribute('download');
btn.value?.removeAttribute('href');
btn.value?.removeAttribute('type');
btn.value?.removeAttribute("download");
btn.value?.removeAttribute("href");
btn.value?.removeAttribute("type");
}
</script>
<style scoped lang="scss">
i.fa::before {
color: var(--bs-dropdown-link-hover-color);
color: var(--bs-dropdown-link-hover-color);
}
</style>

View File

@ -1,58 +1,79 @@
<template>
<a v-if="!state.is_ready" :class="props.classes" @click="download_and_open()" title="T&#233;l&#233;charger">
<a
v-if="!state.is_ready"
:class="props.classes"
@click="download_and_open()"
title="T&#233;l&#233;charger"
>
<i class="fa fa-download"></i>
<template v-if="displayActionStringInButton">Télécharger</template>
</a>
<a v-else :class="props.classes" target="_blank" :type="props.atVersion.type" :download="buildDocumentName()" :href="state.href_url" ref="open_button" title="Ouvrir">
<a
v-else
:class="props.classes"
target="_blank"
:type="props.atVersion.type"
:download="buildDocumentName()"
:href="state.href_url"
ref="open_button"
title="Ouvrir"
>
<i class="fa fa-external-link"></i>
<template v-if="displayActionStringInButton">Ouvrir</template>
</a>
</template>
<script lang="ts" setup>
import {reactive, ref, nextTick, onMounted} from "vue";
import {download_and_decrypt_doc} from "./helpers";
import { reactive, ref, nextTick, onMounted } from "vue";
import { download_and_decrypt_doc } from "./helpers";
import mime from "mime";
import {StoredObject, StoredObjectVersion} from "../../types";
import { StoredObject, StoredObjectVersion } from "../../types";
interface DownloadButtonConfig {
storedObject: StoredObject,
atVersion: StoredObjectVersion,
classes: { [k: string]: boolean },
filename?: string,
storedObject: StoredObject;
atVersion: StoredObjectVersion;
classes: Record<string, boolean>;
filename?: string;
/**
* if true, display the action string into the button. If false, displays only
* the icon
*/
displayActionStringInButton?: boolean,
displayActionStringInButton?: boolean;
/**
* if true, will download directly the file on load
*/
directDownload?: boolean,
directDownload?: boolean;
}
interface DownloadButtonState {
is_ready: boolean,
is_running: boolean,
href_url: string,
is_ready: boolean;
is_running: boolean;
href_url: string;
}
const props = withDefaults(defineProps<DownloadButtonConfig>(), {displayActionStringInButton: true, directDownload: false});
const state: DownloadButtonState = reactive({is_ready: false, is_running: false, href_url: "#"});
const props = withDefaults(defineProps<DownloadButtonConfig>(), {
displayActionStringInButton: true,
directDownload: false,
});
const state: DownloadButtonState = reactive({
is_ready: false,
is_running: false,
href_url: "#",
});
const open_button = ref<HTMLAnchorElement | null>(null);
function buildDocumentName(): string {
let document_name = props.filename ?? props.storedObject.title;
if ('' === document_name) {
document_name = 'document';
if ("" === document_name) {
document_name = "document";
}
const ext = mime.getExtension(props.atVersion.type);
if (null !== ext) {
return document_name + '.' + ext;
return document_name + "." + ext;
}
return document_name;
@ -60,21 +81,24 @@ function buildDocumentName(): string {
async function download_and_open(): Promise<void> {
if (state.is_running) {
console.log('state is running, aborting');
console.log("state is running, aborting");
return;
}
state.is_running = true;
if (state.is_ready) {
console.log('state is ready. This should not happens');
console.log("state is ready. This should not happens");
return;
}
let raw;
try {
raw = await download_and_decrypt_doc(props.storedObject, props.atVersion);
raw = await download_and_decrypt_doc(
props.storedObject,
props.atVersion,
);
} catch (e) {
console.error("error while downloading and decrypting document");
console.error(e);
@ -89,13 +113,13 @@ async function download_and_open(): Promise<void> {
await nextTick();
open_button.value?.click();
console.log('open button should have been clicked');
console.log("open button should have been clicked");
setTimeout(reset_state, 45000);
}
}
function reset_state(): void {
state.href_url = '#';
state.href_url = "#";
state.is_ready = false;
state.is_running = false;
}
@ -109,7 +133,7 @@ onMounted(() => {
<style scoped lang="scss">
i.fa::before {
color: var(--bs-dropdown-link-hover-color);
color: var(--bs-dropdown-link-hover-color);
}
i.fa {
margin-right: 0.5rem;

View File

@ -1,9 +1,11 @@
<script setup lang="ts">
import HistoryButtonModal from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/HistoryButtonModal.vue";
import {StoredObject, StoredObjectVersionWithPointInTime} from "./../../types";
import {computed, reactive, ref, useTemplateRef} from "vue";
import {get_versions} from "./HistoryButton/api";
import {
StoredObject,
StoredObjectVersionWithPointInTime,
} from "./../../types";
import { computed, reactive, ref, useTemplateRef } from "vue";
import { get_versions } from "./HistoryButton/api";
interface HistoryButtonConfig {
storedObject: StoredObject;
@ -16,8 +18,8 @@ interface HistoryButtonState {
}
const props = defineProps<HistoryButtonConfig>();
const state = reactive<HistoryButtonState>({versions: [], loaded: false});
const modal = useTemplateRef<typeof HistoryButtonModal>('modal');
const state = reactive<HistoryButtonState>({ versions: [], loaded: false });
const modal = useTemplateRef<typeof HistoryButtonModal>("modal");
const download_version_and_open_modal = async function (): Promise<void> {
if (null !== modal.value) {
@ -34,20 +36,29 @@ const download_version_and_open_modal = async function (): Promise<void> {
}
state.loaded = true;
}
}
};
const onRestoreVersion = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTime}) => {
const onRestoreVersion = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
state.versions.unshift(newVersion);
}
};
</script>
<template>
<a @click="download_version_and_open_modal" class="dropdown-item">
<history-button-modal ref="modal" :versions="state.versions" :stored-object="storedObject" :can-edit="canEdit" @restore-version="onRestoreVersion"></history-button-modal>
<i class="fa fa-history"></i>
Historique
</a>
<a @click="download_version_and_open_modal" class="dropdown-item">
<history-button-modal
ref="modal"
:versions="state.versions"
:stored-object="storedObject"
:can-edit="canEdit"
@restore-version="onRestoreVersion"
></history-button-modal>
<i class="fa fa-history"></i>
Historique
</a>
</template>
<style scoped lang="scss">

View File

@ -1,7 +1,10 @@
<script setup lang="ts">
import {StoredObject, StoredObjectVersionWithPointInTime} from "./../../../types";
import {
StoredObject,
StoredObjectVersionWithPointInTime,
} from "./../../../types";
import HistoryButtonListItem from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/HistoryButtonListItem.vue";
import {computed, reactive} from "vue";
import { computed, reactive } from "vue";
interface HistoryButtonListConfig {
versions: StoredObjectVersionWithPointInTime[];
@ -10,8 +13,8 @@ interface HistoryButtonListConfig {
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
interface HistoryButtonListState {
/**
@ -22,12 +25,14 @@ interface HistoryButtonListState {
const props = defineProps<HistoryButtonListConfig>();
const state = reactive<HistoryButtonListState>({restored: -1})
const state = reactive<HistoryButtonListState>({ restored: -1 });
const higher_version = computed<number>(() => props.versions.reduce(
(accumulator: number, version: StoredObjectVersionWithPointInTime) => Math.max(accumulator, version.version),
-1
)
const higher_version = computed<number>(() =>
props.versions.reduce(
(accumulator: number, version: StoredObjectVersionWithPointInTime) =>
Math.max(accumulator, version.version),
-1,
),
);
/**
@ -35,11 +40,14 @@ const higher_version = computed<number>(() => props.versions.reduce(
*
* internally, keep track of the newly restored version
*/
const onRestored = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTime}) => {
const onRestored = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
state.restored = newVersion.version;
emit('restoreVersion', {newVersion});
}
emit("restoreVersion", { newVersion });
};
</script>
<template>
@ -59,9 +67,6 @@ const onRestored = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTim
<template v-else>
<p>Chargement des versions</p>
</template>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,11 +1,15 @@
<script setup lang="ts">
import {StoredObject, StoredObjectPointInTime, StoredObjectVersionWithPointInTime} from "./../../../types";
import {
StoredObject,
StoredObjectPointInTime,
StoredObjectVersionWithPointInTime,
} from "./../../../types";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
import {ISOToDatetime} from "./../../../../../../ChillMainBundle/Resources/public/chill/js/date";
import { ISOToDatetime } from "./../../../../../../ChillMainBundle/Resources/public/chill/js/date";
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
import RestoreVersionButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/RestoreVersionButton.vue";
import DownloadButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DownloadButton.vue";
import {computed} from "vue";
import { computed } from "vue";
interface HistoryButtonListItemConfig {
version: StoredObjectVersionWithPointInTime;
@ -15,51 +19,124 @@ interface HistoryButtonListItemConfig {
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
const props = defineProps<HistoryButtonListItemConfig>();
const onRestore = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTime}) => {
emit('restoreVersion', {newVersion});
}
const onRestore = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
emit("restoreVersion", { newVersion });
};
const isKeptBeforeConversion = computed<boolean>(() => props.version["point-in-times"].reduce(
(accumulator: boolean, pit: StoredObjectPointInTime) => accumulator || "keep-before-conversion" === pit.reason,
false
const isKeptBeforeConversion = computed<boolean>(() =>
props.version["point-in-times"].reduce(
(accumulator: boolean, pit: StoredObjectPointInTime) =>
accumulator || "keep-before-conversion" === pit.reason,
false,
),
);
const isRestored = computed<boolean>(() => props.version.version > 0 && null !== props.version["from-restored"]);
const isRestored = computed<boolean>(
() => props.version.version > 0 && null !== props.version["from-restored"],
);
const isDuplicated = computed<boolean>(() => props.version.version === 0 && null !== props.version["from-restored"]);
const classes = computed<{row: true, 'row-hover': true, 'blinking-1': boolean, 'blinking-2': boolean}>(() => ({row: true, 'row-hover': true, 'blinking-1': props.isRestored && 0 === props.version.version % 2, 'blinking-2': props.isRestored && 1 === props.version.version % 2}));
const isDuplicated = computed<boolean>(
() =>
props.version.version === 0 && null !== props.version["from-restored"],
);
const classes = computed<{
row: true;
"row-hover": true;
"blinking-1": boolean;
"blinking-2": boolean;
}>(() => ({
row: true,
"row-hover": true,
"blinking-1": props.isRestored && 0 === props.version.version % 2,
"blinking-2": props.isRestored && 1 === props.version.version % 2,
}));
</script>
<template>
<div :class="classes">
<div class="col-12 tags" v-if="isCurrent || isKeptBeforeConversion || isRestored || isDuplicated">
<span class="badge bg-success" v-if="isCurrent">Version actuelle</span>
<span class="badge bg-info" v-if="isKeptBeforeConversion">Conservée avant conversion dans un autre format</span>
<span class="badge bg-info" v-if="isRestored">Restaurée depuis la version {{ version["from-restored"]?.version + 1 }}</span>
<span class="badge bg-info" v-if="isDuplicated">Dupliqué depuis un autre document</span>
<div :class="classes">
<div
class="col-12 tags"
v-if="
isCurrent ||
isKeptBeforeConversion ||
isRestored ||
isDuplicated
"
>
<span class="badge bg-success" v-if="isCurrent"
>Version actuelle</span
>
<span class="badge bg-info" v-if="isKeptBeforeConversion"
>Conservée avant conversion dans un autre format</span
>
<span class="badge bg-info" v-if="isRestored"
>Restaurée depuis la version
{{ version["from-restored"]?.version + 1 }}</span
>
<span class="badge bg-info" v-if="isDuplicated"
>Dupliqué depuis un autre document</span
>
</div>
<div class="col-12">
<file-icon :type="version.type"></file-icon>
<span
><strong>#{{ version.version + 1 }}</strong></span
>
<template
v-if="version.createdBy !== null && version.createdAt !== null"
><strong v-if="version.version == 0">Créé par</strong
><strong v-else>modifié par</strong>
<span class="badge-user"
><UserRenderBoxBadge
:user="version.createdBy"
></UserRenderBoxBadge
></span>
<strong>à</strong>
{{
$d(ISOToDatetime(version.createdAt.datetime8601), "long")
}}</template
><template
v-if="version.createdBy === null && version.createdAt !== null"
><strong v-if="version.version == 0">Créé le</strong
><strong v-else>modifié le</strong>
{{
$d(ISOToDatetime(version.createdAt.datetime8601), "long")
}}</template
>
</div>
<div class="col-12">
<ul class="record_actions small slim on-version-actions">
<li v-if="canEdit && !isCurrent">
<restore-version-button
:stored-object-version="props.version"
@restore-version="onRestore"
></restore-version-button>
</li>
<li>
<download-button
:stored-object="storedObject"
:at-version="version"
:classes="{
btn: true,
'btn-outline-primary': true,
'btn-sm': true,
}"
:display-action-string-in-button="false"
></download-button>
</li>
</ul>
</div>
</div>
<div class="col-12">
<file-icon :type="version.type"></file-icon> <span><strong>#{{ version.version + 1 }}</strong></span> <template v-if="version.createdBy !== null && version.createdAt !== null"><strong v-if="version.version == 0">Créé par</strong><strong v-else>modifié par</strong> <span class="badge-user"><UserRenderBoxBadge :user="version.createdBy"></UserRenderBoxBadge></span> <strong>à</strong> {{ $d(ISOToDatetime(version.createdAt.datetime8601), 'long') }}</template><template v-if="version.createdBy === null && version.createdAt !== null"><strong v-if="version.version == 0">Créé le</strong><strong v-else>modifié le</strong> {{ $d(ISOToDatetime(version.createdAt.datetime8601), 'long') }}</template>
</div>
<div class="col-12">
<ul class="record_actions small slim on-version-actions">
<li v-if="canEdit && !isCurrent">
<restore-version-button :stored-object-version="props.version" @restore-version="onRestore"></restore-version-button>
</li>
<li>
<download-button :stored-object="storedObject" :at-version="version" :classes="{btn: true, 'btn-outline-primary': true, 'btn-sm': true}" :display-action-string-in-button="false"></download-button>
</li>
</ul>
</div>
</div>
</template>
<style scoped lang="scss">

View File

@ -1,8 +1,11 @@
<script setup lang="ts">
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import {reactive} from "vue";
import { reactive } from "vue";
import HistoryButtonList from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/HistoryButtonList.vue";
import {StoredObject, StoredObjectVersionWithPointInTime} from "./../../../types";
import {
StoredObject,
StoredObjectVersionWithPointInTime,
} from "./../../../types";
interface HistoryButtonListConfig {
versions: StoredObjectVersionWithPointInTime[];
@ -11,22 +14,21 @@ interface HistoryButtonListConfig {
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
interface HistoryButtonModalState {
opened: boolean;
}
const props = defineProps<HistoryButtonListConfig>();
const state = reactive<HistoryButtonModalState>({opened: false});
const state = reactive<HistoryButtonModalState>({ opened: false });
const open = () => {
state.opened = true;
}
defineExpose({open});
};
defineExpose({ open });
</script>
<template>
<Teleport to="body">
@ -36,12 +38,17 @@ defineExpose({open});
</template>
<template v-slot:body>
<p>Les versions sont conservées pendant 90 jours.</p>
<history-button-list :versions="props.versions" :can-edit="canEdit" :stored-object="storedObject" @restore-version="(payload) => emit('restoreVersion', payload)"></history-button-list>
<history-button-list
:versions="props.versions"
:can-edit="canEdit"
:stored-object="storedObject"
@restore-version="
(payload) => emit('restoreVersion', payload)
"
></history-button-list>
</template>
</modal>
</Teleport>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,17 +1,20 @@
<script setup lang="ts">
import {StoredObjectVersionPersisted, StoredObjectVersionWithPointInTime} from "../../../types";
import {useToast} from "vue-toast-notification";
import {restore_version} from "./api";
import {
StoredObjectVersionPersisted,
StoredObjectVersionWithPointInTime,
} from "../../../types";
import { useToast } from "vue-toast-notification";
import { restore_version } from "./api";
interface RestoreVersionButtonProps {
storedObjectVersion: StoredObjectVersionPersisted,
storedObjectVersion: StoredObjectVersionPersisted;
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
const props = defineProps<RestoreVersionButtonProps>()
const props = defineProps<RestoreVersionButtonProps>();
const $toast = useToast();
@ -19,14 +22,18 @@ const restore_version_fn = async () => {
const newVersion = await restore_version(props.storedObjectVersion);
$toast.success("Version restaurée");
emit('restoreVersion', {newVersion});
}
emit("restoreVersion", { newVersion });
};
</script>
<template>
<button class="btn btn-outline-action" @click="restore_version_fn" title="Restaurer"><i class="fa fa-rotate-left"></i> Restaurer</button>
<button
class="btn btn-outline-action"
@click="restore_version_fn"
title="Restaurer"
>
<i class="fa fa-rotate-left"></i> Restaurer
</button>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,20 +1,29 @@
<template>
<a :class="Object.assign(props.classes, {'btn': true})" @click="beforeLeave($event)" :href="build_wopi_editor_link(props.storedObject.uuid, props.returnPath)">
<i class="fa fa-paragraph"></i>
Editer en ligne
</a>
<a
:class="Object.assign(props.classes, { btn: true })"
@click="beforeLeave($event)"
:href="
build_wopi_editor_link(props.storedObject.uuid, props.returnPath)
"
>
<i class="fa fa-paragraph"></i>
Editer en ligne
</a>
</template>
<script lang="ts" setup>
import WopiEditButton from "./WopiEditButton.vue";
import {build_wopi_editor_link} from "./helpers";
import {StoredObject, WopiEditButtonExecutableBeforeLeaveFunction} from "../../types";
import { build_wopi_editor_link } from "./helpers";
import {
StoredObject,
WopiEditButtonExecutableBeforeLeaveFunction,
} from "../../types";
interface WopiEditButtonConfig {
storedObject: StoredObject,
returnPath?: string,
classes: {[k: string] : boolean},
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction,
storedObject: StoredObject;
returnPath?: string;
classes: Record<string, boolean>;
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction;
}
const props = defineProps<WopiEditButtonConfig>();
@ -22,25 +31,24 @@ const props = defineProps<WopiEditButtonConfig>();
let executed = false;
async function beforeLeave(event: Event): Promise<true> {
if (props.executeBeforeLeave === undefined || executed === true) {
if (props.executeBeforeLeave === undefined || executed === true) {
return Promise.resolve(true);
}
event.preventDefault();
await props.executeBeforeLeave();
executed = true;
const link = event.target as HTMLAnchorElement;
link.click();
return Promise.resolve(true);
}
event.preventDefault();
await props.executeBeforeLeave();
executed = true;
const link = event.target as HTMLAnchorElement;
link.click();
return Promise.resolve(true);
}
</script>
<style scoped lang="scss">
i.fa::before {
color: var(--bs-dropdown-link-hover-color);
color: var(--bs-dropdown-link-hover-color);
}
</style>

View File

@ -1,7 +1,7 @@
import { createApp } from 'vue';
import PickEntity from 'ChillMainAssets/vuejs/PickEntity/PickEntity.vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
import { appMessages } from 'ChillMainAssets/vuejs/PickEntity/i18n';
import { createApp } from "vue";
import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
import { appMessages } from "ChillMainAssets/vuejs/PickEntity/i18n";
const i18n = _createI18n(appMessages);
@ -9,158 +9,172 @@ let appsOnPage = new Map();
let appsPerInput = new Map();
function loadDynamicPicker(element) {
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
apps.forEach(function (el) {
const isMultiple = parseInt(el.dataset.multiple) === 1,
uniqId = el.dataset.uniqid,
input = element.querySelector(
'[data-input-uniqid="' + el.dataset.uniqid + '"]',
),
// the "picked" will always be an array, even if multiple is false
picked = isMultiple
? JSON.parse(input.value)
: input.value === "[]" || input.value === ""
? null
: [JSON.parse(input.value)];
(suggested = JSON.parse(el.dataset.suggested)),
(as_id = parseInt(el.dataset.asId) === 1),
(submit_on_adding_new_entity =
parseInt(el.dataset.submitOnAddingNewEntity) === 1);
label = el.dataset.label;
apps.forEach(function(el) {
if (!isMultiple) {
if (input.value === "[]") {
input.value = null;
}
}
const
isMultiple = parseInt(el.dataset.multiple) === 1,
uniqId = el.dataset.uniqid,
input = element.querySelector('[data-input-uniqid="'+ el.dataset.uniqid +'"]'),
// the "picked" will always be an array, even if multiple is false
picked = isMultiple ?
JSON.parse(input.value) : (
(input.value === '[]' || input.value === '') ?
null : [ JSON.parse(input.value) ]
)
suggested = JSON.parse(el.dataset.suggested),
as_id = parseInt(el.dataset.asId) === 1,
submit_on_adding_new_entity = parseInt(el.dataset.submitOnAddingNewEntity) === 1
label = el.dataset.label;
if (!isMultiple) {
if (input.value === '[]'){
input.value = null;
}
}
const app = createApp({
template: '<pick-entity ' +
':multiple="multiple" ' +
':types="types" ' +
':picked="picked" ' +
':uniqid="uniqid" ' +
':suggested="notPickedSuggested" ' +
':label="label" ' +
'@addNewEntity="addNewEntity" ' +
'@removeEntity="removeEntity" ' +
'@addNewEntityProcessEnded="addNewEntityProcessEnded"' +
'></pick-entity>',
components: {
PickEntity,
},
data() {
return {
multiple: isMultiple,
types: JSON.parse(el.dataset.types),
picked: picked === null ? [] : picked,
uniqid: el.dataset.uniqid,
suggested,
as_id,
submit_on_adding_new_entity,
label,
}
},
computed: {
notPickedSuggested() {
const pickedIds = new Set();
for (const p of this.picked) {
pickedIds.add(`${p.type}${p.id}`);
}
return this.suggested.filter(e => !pickedIds.has(`${e.type}${e.id}`))
const app = createApp({
template:
"<pick-entity " +
':multiple="multiple" ' +
':types="types" ' +
':picked="picked" ' +
':uniqid="uniqid" ' +
':suggested="notPickedSuggested" ' +
':label="label" ' +
'@addNewEntity="addNewEntity" ' +
'@removeEntity="removeEntity" ' +
'@addNewEntityProcessEnded="addNewEntityProcessEnded"' +
"></pick-entity>",
components: {
PickEntity,
},
data() {
return {
multiple: isMultiple,
types: JSON.parse(el.dataset.types),
picked: picked === null ? [] : picked,
uniqid: el.dataset.uniqid,
suggested,
as_id,
submit_on_adding_new_entity,
label,
};
},
computed: {
notPickedSuggested() {
const pickedIds = new Set();
for (const p of this.picked) {
pickedIds.add(`${p.type}${p.id}`);
}
return this.suggested.filter(
(e) => !pickedIds.has(`${e.type}${e.id}`),
);
},
},
methods: {
addNewEntity({ entity }) {
if (this.multiple) {
if (
!this.picked.some((el) => {
return el.type === entity.type && el.id === entity.id;
})
) {
this.picked.push(entity);
if (!as_id) {
input.value = JSON.stringify(this.picked);
} else {
const ids = this.picked.map((el) => el.id);
input.value = ids.join(",");
}
},
methods: {
addNewEntity({entity}) {
if (this.multiple) {
if (!this.picked.some(el => {
return el.type === entity.type && el.id === entity.id;
})) {
this.picked.push(entity);
if (!as_id) {
input.value = JSON.stringify(this.picked);
} else {
const ids = this.picked.map(el => el.id);
input.value = ids.join(',');
}
console.log(entity)
}
} else {
if (!this.picked.some(el => {
return el.type === entity.type && el.id === entity.id;
})) {
this.picked.splice(0, this.picked.length);
this.picked.push(entity);
if (!as_id) {
input.value = JSON.stringify(this.picked[0]);
} else {
input.value = this.picked.map(el => el.id);
}
}
}
},
addNewEntityProcessEnded() {
if (this.submit_on_adding_new_entity) {
input.form.submit();
}
},
removeEntity({entity}) {
if (-1 === this.suggested.findIndex(e => e.type === entity.type && e.id === entity.id)) {
this.suggested.push(entity);
}
this.picked = this.picked.filter(e => !(e.type === entity.type && e.id === entity.id));
if (this.multiple) {
input.value = JSON.stringify(this.picked);
} else {
input.value = "";
}
},
console.log(entity);
}
})
.use(i18n)
.mount(el);
} else {
if (
!this.picked.some((el) => {
return el.type === entity.type && el.id === entity.id;
})
) {
this.picked.splice(0, this.picked.length);
this.picked.push(entity);
if (!as_id) {
input.value = JSON.stringify(this.picked[0]);
} else {
input.value = this.picked.map((el) => el.id);
}
}
}
},
addNewEntityProcessEnded() {
if (this.submit_on_adding_new_entity) {
input.form.submit();
}
},
removeEntity({ entity }) {
if (
-1 ===
this.suggested.findIndex(
(e) => e.type === entity.type && e.id === entity.id,
)
) {
this.suggested.push(entity);
}
this.picked = this.picked.filter(
(e) => !(e.type === entity.type && e.id === entity.id),
);
if (this.multiple) {
input.value = JSON.stringify(this.picked);
} else {
input.value = "";
}
},
},
})
.use(i18n)
.mount(el);
appsOnPage.set(uniqId, app);
appsPerInput.set(input.name, app);
});
appsOnPage.set(uniqId, app);
appsPerInput.set(input.name, app);
});
}
document.addEventListener('show-hide-show', function(e) {
loadDynamicPicker(e.detail.container)
document.addEventListener("show-hide-show", function (e) {
loadDynamicPicker(e.detail.container);
});
document.addEventListener('show-hide-hide', function(e) {
console.log('hiding event caught')
e.detail.container.querySelectorAll('[data-module="pick-dynamic"]').forEach((el) => {
let uniqId = el.dataset.uniqid;
if (appsOnPage.has(uniqId)) {
appsOnPage.get(uniqId).unmount();
appsOnPage.delete(uniqId);
}
})
});
document.addEventListener('pick-entity-type-action', function (e) {
console.log('pick entity event', e);
if (!appsPerInput.has(e.detail.name)) {
console.error('no app with this name');
return;
}
const app = appsPerInput.get(e.detail.name);
if (e.detail.action === 'add') {
app.addNewEntity(e.detail.entity);
} else if (e.detail.action === 'remove') {
app.removeEntity(e.detail.entity);
} else {
console.error('action not supported: '+e.detail.action);
document.addEventListener("show-hide-hide", function (e) {
console.log("hiding event caught");
e.detail.container
.querySelectorAll('[data-module="pick-dynamic"]')
.forEach((el) => {
let uniqId = el.dataset.uniqid;
if (appsOnPage.has(uniqId)) {
appsOnPage.get(uniqId).unmount();
appsOnPage.delete(uniqId);
}
});
});
document.addEventListener('DOMContentLoaded', function(e) {
loadDynamicPicker(document)
})
document.addEventListener("pick-entity-type-action", function (e) {
console.log("pick entity event", e);
if (!appsPerInput.has(e.detail.name)) {
console.error("no app with this name");
return;
}
const app = appsPerInput.get(e.detail.name);
if (e.detail.action === "add") {
app.addNewEntity(e.detail.entity);
} else if (e.detail.action === "remove") {
app.removeEntity(e.detail.entity);
} else {
console.error("action not supported: " + e.detail.action);
}
});
document.addEventListener("DOMContentLoaded", function (e) {
loadDynamicPicker(document);
});
window.loadDynamicPicker = loadDynamicPicker;

View File

@ -1,174 +1,180 @@
import {ShowHide} from 'ChillMainAssets/lib/show_hide/show_hide.js';
import { ShowHide } from "ChillMainAssets/lib/show_hide/show_hide.js";
window.addEventListener('DOMContentLoaded', function() {
const
divTransitions = document.querySelector('#transitions'),
futureDestUsersContainer = document.querySelector('#futureDests'),
personSignatureField = document.querySelector('#person-signature-field'),
userSignatureField = document.querySelector('#user-signature-field'),
signatureTypeChoices = document.querySelector('#signature-type-choice'),
personChoice = document.querySelector('#workflow_step_isPersonOrUserSignature_0'),
userChoice = document.querySelector('#workflow_step_isPersonOrUserSignature_1'),
signatureZone = document.querySelector('#signature-zone'),
transitionFilterContainer = document.querySelector('#transitionFilter'),
transitionsContainer = document.querySelector('#transitions'),
sendExternalContainer = document.querySelector('#sendExternalContainer')
;
window.addEventListener("DOMContentLoaded", function () {
const divTransitions = document.querySelector("#transitions"),
futureDestUsersContainer = document.querySelector("#futureDests"),
personSignatureField = document.querySelector("#person-signature-field"),
userSignatureField = document.querySelector("#user-signature-field"),
signatureTypeChoices = document.querySelector("#signature-type-choice"),
personChoice = document.querySelector(
"#workflow_step_isPersonOrUserSignature_0",
),
userChoice = document.querySelector(
"#workflow_step_isPersonOrUserSignature_1",
),
signatureZone = document.querySelector("#signature-zone"),
transitionFilterContainer = document.querySelector("#transitionFilter"),
transitionsContainer = document.querySelector("#transitions"),
sendExternalContainer = document.querySelector("#sendExternalContainer");
// ShowHide instance for future dest users
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [futureDestUsersContainer],
test: function (froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll("input")) {
if (input.checked) {
if ("1" === input.dataset.toFinal) {
return false;
}
// ShowHide instance for future dest users
if ("1" === input.dataset.isSentExternal) {
return false;
}
const inputData = JSON.parse(
input.getAttribute("data-is-signature"),
);
if (inputData.includes("person") || inputData.includes("user")) {
return false;
} else {
personChoice.checked = false;
userChoice.checked = false;
return true;
}
}
}
}
return false;
},
});
// ShowHide instance for send external
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [sendExternalContainer],
test: function (froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll("input")) {
if (input.checked) {
if ("1" === input.dataset.isSentExternal) {
return true;
}
}
}
}
return false;
},
});
// ShowHide signature zone
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [signatureZone],
test: function (froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll("input")) {
if (input.checked) {
const inputData = JSON.parse(
input.getAttribute("data-is-signature"),
);
if (inputData.includes("person") || inputData.includes("user")) {
return true;
}
}
}
}
return false;
},
});
// ShowHides for personSignatureField or userSignatureField within signature zone
new ShowHide({
debug: false,
froms: [signatureTypeChoices],
container: [personSignatureField],
test: function (froms, event) {
for (let container of froms) {
return personChoice.checked;
}
return false;
},
});
new ShowHide({
debug: false,
froms: [signatureTypeChoices],
container: [userSignatureField],
test: function (froms, event) {
for (let container of froms) {
return userChoice.checked;
}
return false;
},
});
if (null !== divTransitions) {
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [futureDestUsersContainer],
test: function(froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
test: function (divs, arg2, arg3) {
for (let div of divs) {
for (let input of div.querySelectorAll("input")) {
if (input.checked) {
if ('1' === input.dataset.toFinal) {
return false;
}
if ('1' === input.dataset.isSentExternal) {
return false;
}
const inputData = JSON.parse(input.getAttribute('data-is-signature'))
if (inputData.includes('person') || inputData.includes('user')) {
if (input.dataset.toFinal === "1") {
return false;
} else {
personChoice.checked = false
userChoice.checked = false
return true;
}
}
}
}
return false;
}
});
// ShowHide instance for send external
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [sendExternalContainer],
test: function(froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
if (input.checked) {
if ('1' === input.dataset.isSentExternal) {
return true;
}
}
}
}
return false;
}
})
// ShowHide signature zone
new ShowHide({
debug: false,
load_event: null,
froms: [divTransitions],
container: [signatureZone],
test: function(froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
if (input.checked) {
const inputData = JSON.parse(input.getAttribute('data-is-signature'))
if (inputData.includes('person') || inputData.includes('user')) {
return true;
}
}
}
}
return false;
}
});
// ShowHides for personSignatureField or userSignatureField within signature zone
new ShowHide({
debug: false,
froms: [signatureTypeChoices],
container: [personSignatureField],
test: function(froms, event) {
for (let container of froms) {
return personChoice.checked;
}
return false;
return true;
},
});
}
new ShowHide({
debug: false,
froms: [signatureTypeChoices],
container: [userSignatureField],
test: function(froms, event) {
for (let container of froms) {
return userChoice.checked;
}
return false;
},
});
if (null !== transitionFilterContainer) {
transitionsContainer
.querySelectorAll(".form-check")
.forEach(function (row) {
const isForward = row.querySelector("input").dataset.isForward;
if (null !== divTransitions) {
new ShowHide({
new ShowHide({
load_event: null,
froms: [divTransitions],
container: [futureDestUsersContainer],
test: function(divs, arg2, arg3) {
for (let div of divs) {
for (let input of div.querySelectorAll('input')) {
if (input.checked) {
if (input.dataset.toFinal === "1") {
return false;
} else {
return true;
}
}
}
froms: [transitionFilterContainer],
container: row,
test: function (containers) {
for (let container of containers) {
for (let input of container.querySelectorAll("input")) {
if (input.checked) {
return isForward === input.value;
}
}
return true;
}
return true;
},
toggle_callback: function (c, dir) {
for (let div of c) {
let input = div.querySelector("input");
if ("hide" === dir) {
input.checked = false;
input.disabled = true;
} else {
input.disabled = false;
}
}
},
});
}
if (null !== transitionFilterContainer) {
transitionsContainer.querySelectorAll('.form-check').forEach(function(row) {
const isForward = row.querySelector('input').dataset.isForward;
new ShowHide({
load_event: null,
froms: [transitionFilterContainer],
container: row,
test: function (containers) {
for (let container of containers) {
for (let input of container.querySelectorAll('input')) {
if (input.checked) {
return isForward === input.value;
}
}
}
return true;
},
toggle_callback: function (c, dir) {
for (let div of c) {
let input = div.querySelector('input');
if ('hide' === dir) {
input.checked = false;
input.disabled = true;
} else {
input.disabled = false;
}
}
},
});
});
}
});
}
});

View File

@ -28,7 +28,11 @@
/>
<span class="mx-2">{{ getStep(w) }}</span>
</div>
<span v-if="w.isOnHoldAtCurrentStep" class="badge bg-success rounded-pill">{{ $t('on_hold') }}</span>
<span
v-if="w.isOnHoldAtCurrentStep"
class="badge bg-success rounded-pill"
>{{ $t("on_hold") }}</span
>
</div>
</td>
<td v-if="w.datas.persons !== null">

View File

@ -1,83 +1,89 @@
const appMessages = {
fr: {
main_title: "Vue d'ensemble",
my_works: {
tab: "Mes actions",
description: "Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance.",
},
my_evaluations: {
tab: "Mes évaluations",
description: "Liste des évaluations dont je suis référent et qui arrivent à échéance.",
},
my_tasks: {
tab: "Mes tâches",
description_alert: "Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée.",
description_warning: "Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
},
my_accompanying_courses: {
tab: "Mes nouveaux parcours",
description: "Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours.",
},
my_notifications: {
tab: "Mes nouvelles notifications",
description: "Liste des notifications reçues et non lues.",
},
my_workflows: {
tab: "Mes workflows",
description: "Liste des workflows en attente d'une action.",
description_cc: "Liste des workflows dont je suis en copie."
},
opening_date: "Date d'ouverture",
social_issues: "Problématiques sociales",
concerned_persons: "Usagers concernés",
max_date: "Date d'échéance",
warning_date: "Date de rappel",
evaluation: "Évaluation",
task: "Tâche",
Date: "Date",
From: "Expéditeur",
Subject: "Objet",
Entity: "Associé à",
Step: "Étape",
concerned_users: "Usagers concernés",
Object_workflow: "Objet du workflow",
on_hold: "En attente",
show_entity: "Voir {entity}",
the_activity: "l'échange",
the_course: "le parcours",
the_action: "l'action",
the_evaluation: "l'évaluation",
the_evaluation_document: "le document",
the_task: "la tâche",
the_workflow: "le workflow",
StartDate: "Date d'ouverture",
SocialAction: "Action d'accompagnement",
no_data: "Aucun résultats",
no_dashboard: "Pas de tableaux de bord",
counter: {
unread_notifications: "{n} notification non lue | {n} notifications non lues",
assignated_courses: "{n} parcours récent assigné | {n} parcours récents assignés",
assignated_actions: "{n} action assignée | {n} actions assignées",
assignated_evaluations: "{n} évaluation assignée | {n} évaluations assignées",
alert_tasks: "{n} tâche en rappel | {n} tâches en rappel",
warning_tasks: "{n} tâche à échéance | {n} tâches à échéance",
},
emergency: "Urgent",
confidential: "Confidentiel",
automatic_notification: "Notification automatique",
widget: {
news: {
title: "Actualités",
readMore: "Lire la suite",
date: "Date",
none: "Aucune actualité"
}
}
}
fr: {
main_title: "Vue d'ensemble",
my_works: {
tab: "Mes actions",
description:
"Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance.",
},
my_evaluations: {
tab: "Mes évaluations",
description:
"Liste des évaluations dont je suis référent et qui arrivent à échéance.",
},
my_tasks: {
tab: "Mes tâches",
description_alert:
"Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée.",
description_warning:
"Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
},
my_accompanying_courses: {
tab: "Mes nouveaux parcours",
description:
"Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours.",
},
my_notifications: {
tab: "Mes nouvelles notifications",
description: "Liste des notifications reçues et non lues.",
},
my_workflows: {
tab: "Mes workflows",
description: "Liste des workflows en attente d'une action.",
description_cc: "Liste des workflows dont je suis en copie.",
},
opening_date: "Date d'ouverture",
social_issues: "Problématiques sociales",
concerned_persons: "Usagers concernés",
max_date: "Date d'échéance",
warning_date: "Date de rappel",
evaluation: "Évaluation",
task: "Tâche",
Date: "Date",
From: "Expéditeur",
Subject: "Objet",
Entity: "Associé à",
Step: "Étape",
concerned_users: "Usagers concernés",
Object_workflow: "Objet du workflow",
on_hold: "En attente",
show_entity: "Voir {entity}",
the_activity: "l'échange",
the_course: "le parcours",
the_action: "l'action",
the_evaluation: "l'évaluation",
the_evaluation_document: "le document",
the_task: "la tâche",
the_workflow: "le workflow",
StartDate: "Date d'ouverture",
SocialAction: "Action d'accompagnement",
no_data: "Aucun résultats",
no_dashboard: "Pas de tableaux de bord",
counter: {
unread_notifications:
"{n} notification non lue | {n} notifications non lues",
assignated_courses:
"{n} parcours récent assigné | {n} parcours récents assignés",
assignated_actions: "{n} action assignée | {n} actions assignées",
assignated_evaluations:
"{n} évaluation assignée | {n} évaluations assignées",
alert_tasks: "{n} tâche en rappel | {n} tâches en rappel",
warning_tasks: "{n} tâche à échéance | {n} tâches à échéance",
},
emergency: "Urgent",
confidential: "Confidentiel",
automatic_notification: "Notification automatique",
widget: {
news: {
title: "Actualités",
readMore: "Lire la suite",
date: "Date",
none: "Aucune actualité",
},
},
},
};
Object.assign(appMessages.fr);
export {
appMessages
};
export { appMessages };

View File

@ -1,6 +1,6 @@
<template>
<ul :class="listClasses" v-if="picked.length && displayPicked">
<li v-for="p in picked" @click="removeEntity(p)" :key="p.type+p.id">
<li v-for="p in picked" @click="removeEntity(p)" :key="p.type + p.id">
<span class="chill_denomination">{{ p.text }}</span>
</li>
</ul>
@ -18,7 +18,9 @@
</li>
</ul>
<ul class="list-suggest add-items inline">
<li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)"><span>{{ s.text }}</span></li>
<li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)">
<span>{{ s.text }}</span>
</li>
</ul>
</template>
@ -49,86 +51,92 @@ export default {
default: true,
},
displayPicked: {
// display picked entities.
type: Boolean,
default: true,
// display picked entities.
type: Boolean,
default: true,
},
suggested: {
type: Array,
default: []
type: Array,
default: [],
},
label: {
type: String,
required: false,
}
},
},
emits: ['addNewEntity', 'removeEntity', 'addNewEntityProcessEnded'],
emits: ["addNewEntity", "removeEntity", "addNewEntityProcessEnded"],
components: {
AddPersons,
},
data() {
return {
key: ''
key: "",
};
},
computed: {
addPersonsOptions() {
return {
uniq: !this.multiple,
type: this.types,
priority: null,
button: {
size: 'btn-sm',
class: 'btn-submit',
},
};
},
translatedListOfTypes() {
if (this.label !== '') {
return this.label;
}
addPersonsOptions() {
return {
uniq: !this.multiple,
type: this.types,
priority: null,
button: {
size: "btn-sm",
class: "btn-submit",
},
};
},
translatedListOfTypes() {
if (this.label !== "") {
return this.label;
}
let trans = [];
this.types.forEach(t => {
if (this.$props.multiple) {
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
} else {
trans.push(appMessages.fr.pick_entity[t + '_one'].toLowerCase());
}
})
let trans = [];
this.types.forEach((t) => {
if (this.$props.multiple) {
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
} else {
trans.push(
appMessages.fr.pick_entity[t + "_one"].toLowerCase(),
);
}
});
if (this.$props.multiple) {
return appMessages.fr.pick_entity.modal_title + trans.join(', ');
} else {
return appMessages.fr.pick_entity.modal_title_one + trans.join(', ');
}
},
listClasses() {
return {
'list-suggest': true,
'remove-items': this.$props.removableIfSet,
};
},
if (this.$props.multiple) {
return (
appMessages.fr.pick_entity.modal_title + trans.join(", ")
);
} else {
return (
appMessages.fr.pick_entity.modal_title_one +
trans.join(", ")
);
}
},
listClasses() {
return {
"list-suggest": true,
"remove-items": this.$props.removableIfSet,
};
},
},
methods: {
addNewSuggested(entity) {
this.$emit('addNewEntity', {entity: entity});
},
addNewEntity({ selected, modal }) {
selected.forEach((item) => {
this.$emit('addNewEntity', { entity: item.result});
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
this.$emit('addNewEntityProcessEnded');
},
removeEntity(entity) {
if (!this.$props.removableIfSet) {
return;
}
this.$emit('removeEntity',{ entity: entity });
}
addNewSuggested(entity) {
this.$emit("addNewEntity", { entity: entity });
},
addNewEntity({ selected, modal }) {
selected.forEach((item) => {
this.$emit("addNewEntity", { entity: item.result });
}, this);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
this.$emit("addNewEntityProcessEnded");
},
removeEntity(entity) {
if (!this.$props.removableIfSet) {
return;
}
this.$emit("removeEntity", { entity: entity });
},
},
}
};
</script>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import {UserGroup} from "../../../types";
import {computed} from "vue";
import { UserGroup } from "../../../types";
import { computed } from "vue";
interface UserGroupRenderBoxProps {
userGroup: UserGroup;
@ -8,19 +8,18 @@ interface UserGroupRenderBoxProps {
const props = defineProps<UserGroupRenderBoxProps>();
const styles = computed<{color: string, "background-color": string}>(() => {
const styles = computed<{ color: string; "background-color": string }>(() => {
return {
color: props.userGroup.foregroundColor,
"background-color": props.userGroup.backgroundColor,
}
};
});
</script>
<template>
<span class="badge-user-group" :style="styles">{{ userGroup.label.fr }}</span>
<span class="badge-user-group" :style="styles">{{
userGroup.label.fr
}}</span>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,140 +1,163 @@
<template>
<div class="flex-table workflow" id="workflow-list">
<div v-for="(w, i) in workflows" :key="`workflow-${i}`"
class="item-bloc">
<div class="flex-table workflow" id="workflow-list">
<div
v-for="(w, i) in workflows"
:key="`workflow-${i}`"
class="item-bloc"
>
<div>
<div class="item-row col">
<h2>{{ w.title }}</h2>
<div class="flex-grow-1 ms-3 h3">
<div class="visually-hidden">
{{ w.relatedEntityClass }}
{{ w.relatedEntityId }}
</div>
</div>
</div>
<div>
<div class="item-row col">
<h2>{{ w.title }}</h2>
<div class="flex-grow-1 ms-3 h3">
<div class="visually-hidden">
{{ w.relatedEntityClass }}
{{ w.relatedEntityId }}
</div>
</div>
<div class="breadcrumb">
<template v-for="(step, j) in w.steps" :key="`step-${j}`">
<span
class="mx-2"
tabindex="0"
data-bs-trigger="focus hover"
data-bs-toggle="popover"
data-bs-placement="bottom"
data-bs-custom-class="workflow-transition"
:title="getPopTitle(step)"
:data-bs-content="getPopContent(step)"
>
<i
v-if="step.currentStep.name === 'initial'"
class="fa fa-circle me-1 text-chill-yellow"
>
</i>
<i
v-if="step.isFreezed"
class="fa fa-snowflake-o fa-sm me-1"
>
</i>
{{ step.currentStep.text }}
</span>
<span v-if="j !== Object.keys(w.steps).length - 1">
</span>
</template>
</div>
<span
v-if="w.isOnHoldAtCurrentStep"
class="badge bg-success rounded-pill"
>{{ $t("on_hold") }}</span
>
</div>
<div class="breadcrumb">
<template v-for="(step, j) in w.steps" :key="`step-${j}`">
<span class="mx-2"
tabindex="0"
data-bs-trigger="focus hover"
data-bs-toggle="popover"
data-bs-placement="bottom"
data-bs-custom-class="workflow-transition"
:title="getPopTitle(step)"
:data-bs-content="getPopContent(step)">
<i v-if="step.currentStep.name === 'initial'"
class="fa fa-circle me-1 text-chill-yellow">
</i>
<i v-if="step.isFreezed"
class="fa fa-snowflake-o fa-sm me-1">
</i>
{{ step.currentStep.text }}
</span>
<span v-if="j !== Object.keys(w.steps).length - 1">
</span>
</template>
<div class="item-row">
<div class="item-col flex-grow-1">
<p v-if="isUserSubscribedToStep(w)">
<i class="fa fa-check fa-fw"></i>
{{ $t("you_subscribed_to_all_steps") }}
</p>
<p v-if="isUserSubscribedToFinal(w)">
<i class="fa fa-check fa-fw"></i>
{{ $t("you_subscribed_to_final_step") }}
</p>
</div>
<div class="item-col">
<ul class="record_actions">
<li>
<a
:href="goToUrl(w)"
class="btn btn-sm btn-show"
:title="$t('action.show')"
></a>
</li>
</ul>
</div>
</div>
<span v-if="w.isOnHoldAtCurrentStep" class="badge bg-success rounded-pill">{{ $t('on_hold') }}</span>
</div>
<div class="item-row">
<div class="item-col flex-grow-1">
<p v-if="isUserSubscribedToStep(w)">
<i class="fa fa-check fa-fw"></i>
{{ $t('you_subscribed_to_all_steps') }}
</p>
<p v-if="isUserSubscribedToFinal(w)">
<i class="fa fa-check fa-fw"></i>
{{ $t('you_subscribed_to_final_step') }}
</p>
</div>
<div class="item-col">
<ul class="record_actions">
<li>
<a :href="goToUrl(w)" class="btn btn-sm btn-show" :title="$t('action.show')"></a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Popover from 'bootstrap/js/src/popover';
import Popover from "bootstrap/js/src/popover";
const i18n = {
messages: {
fr: {
you_subscribed_to_all_steps: "Vous recevrez une notification à chaque étape",
you_subscribed_to_final_step: "Vous recevrez une notification à l'étape finale",
by: "Par",
at: "Le",
on_hold: "En attente"
}
}
}
messages: {
fr: {
you_subscribed_to_all_steps:
"Vous recevrez une notification à chaque étape",
you_subscribed_to_final_step:
"Vous recevrez une notification à l'étape finale",
by: "Par",
at: "Le",
on_hold: "En attente",
},
},
};
export default {
name: "ListWorkflow",
i18n: i18n,
props: {
workflows: {
type: Array,
required: true,
}
},
methods: {
goToUrl(w) {
return `/fr/main/workflow/${w.id}/show`;
},
getPopTitle(step) {
if (step.transitionPrevious != null) {
//console.log(step.transitionPrevious.text);
let freezed = step.isFreezed ? `<i class="fa fa-snowflake-o fa-sm me-1"></i>` : ``;
return `${freezed}${step.transitionPrevious.text}`;
}
},
getPopContent(step) {
if (step.transitionPrevious != null) {
if (step.transitionPreviousBy !== null) {
return `<ul class="small_in_title">
name: "ListWorkflow",
i18n: i18n,
props: {
workflows: {
type: Array,
required: true,
},
},
methods: {
goToUrl(w) {
return `/fr/main/workflow/${w.id}/show`;
},
getPopTitle(step) {
if (step.transitionPrevious != null) {
//console.log(step.transitionPrevious.text);
let freezed = step.isFreezed
? `<i class="fa fa-snowflake-o fa-sm me-1"></i>`
: ``;
return `${freezed}${step.transitionPrevious.text}`;
}
},
getPopContent(step) {
if (step.transitionPrevious != null) {
if (step.transitionPreviousBy !== null) {
return `<ul class="small_in_title">
<li><span class="item-key">${i18n.messages.fr.by} : </span><b>${step.transitionPreviousBy.text}</b></li>
<li><span class="item-key">${i18n.messages.fr.at} : </span><b>${this.formatDate(step.transitionPreviousAt.datetime)}</b></li>
</ul>`
;
} else {
return `<ul class="small_in_title">
</ul>`;
} else {
return `<ul class="small_in_title">
<li><span class="item-key">${i18n.messages.fr.at} : </span><b>${this.formatDate(step.transitionPreviousAt.datetime)}</b></li>
</ul>`
}
}
},
formatDate(datetime) {
return datetime.split('T')[0] +' '+ datetime.split('T')[1].substring(0,5)
},
isUserSubscribedToStep(w) {
// todo
return false;
},
isUserSubscribedToFinal(w) {
// todo
return false;
},
},
mounted() {
const triggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
const popoverList = triggerList.map(function (el) {
//console.log('popover', el)
return new Popover(el, {
html: true,
});
});
}
}
</ul>`;
}
}
},
formatDate(datetime) {
return (
datetime.split("T")[0] +
" " +
datetime.split("T")[1].substring(0, 5)
);
},
isUserSubscribedToStep(w) {
// todo
return false;
},
isUserSubscribedToFinal(w) {
// todo
return false;
},
},
mounted() {
const triggerList = [].slice.call(
document.querySelectorAll('[data-bs-toggle="popover"]'),
);
const popoverList = triggerList.map(function (el) {
//console.log('popover', el)
return new Popover(el, {
html: true,
});
});
},
};
</script>

View File

@ -1,126 +1,129 @@
<template>
<pick-workflow
:relatedEntityClass="this.relatedEntityClass"
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
:goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
:countExistingWorkflows="countWorkflows"
@go-to-generate-workflow="goToGenerateWorkflow"
@click-open-list="openModal"
></pick-workflow>
<pick-workflow
:relatedEntityClass="this.relatedEntityClass"
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
:goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
:countExistingWorkflows="countWorkflows"
@go-to-generate-workflow="goToGenerateWorkflow"
@click-open-list="openModal"
></pick-workflow>
<teleport to="body">
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
<teleport to="body">
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template v-slot:header>
<h2 class="modal-title">{{ $t("workflow_list") }}</h2>
</template>
<template v-slot:header>
<h2 class="modal-title">{{ $t('workflow_list') }}</h2>
</template>
<template v-slot:body>
<list-workflow-vue :workflows="workflows"></list-workflow-vue>
</template>
<template v-slot:body>
<list-workflow-vue
:workflows="workflows"
></list-workflow-vue>
</template>
<template v-slot:footer>
<pick-workflow v-if="allowCreate"
:relatedEntityClass="this.relatedEntityClass"
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
:goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
:countExistingWorkflows="countWorkflows"
:embedded-within-list-modal="true"
@go-to-generate-workflow="this.goToGenerateWorkflow"
></pick-workflow>
</template>
</modal>
</teleport>
<template v-slot:footer>
<pick-workflow
v-if="allowCreate"
:relatedEntityClass="this.relatedEntityClass"
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="
this.$props.preventDefaultMoveToGenerate
"
:goToGenerateWorkflowPayload="
this.goToGenerateWorkflowPayload
"
:countExistingWorkflows="countWorkflows"
:embedded-within-list-modal="true"
@go-to-generate-workflow="this.goToGenerateWorkflow"
></pick-workflow>
</template>
</modal>
</teleport>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import PickWorkflow from 'ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue';
import ListWorkflowVue from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflow.vue';
import Modal from "ChillMainAssets/vuejs/_components/Modal";
import PickWorkflow from "ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue";
import ListWorkflowVue from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflow.vue";
export default {
name: "ListWorkflowModal",
components: {
Modal,
PickWorkflow,
ListWorkflowVue
},
emits: ['goToGenerateWorkflow'],
props: {
workflows: {
type: Array,
required: true,
},
allowCreate: {
type: Boolean,
required: true,
},
relatedEntityClass: {
type: String,
required: true,
},
relatedEntityId: {
type: Number,
required: false,
},
workflowsAvailables: {
type: Array,
required: true,
},
preventDefaultMoveToGenerate: {
type: Boolean,
required: false,
default: false,
},
goToGenerateWorkflowPayload: {
required: false,
default: {}
},
},
name: "ListWorkflowModal",
components: {
Modal,
PickWorkflow,
ListWorkflowVue,
},
emits: ["goToGenerateWorkflow"],
props: {
workflows: {
type: Array,
required: true,
},
allowCreate: {
type: Boolean,
required: true,
},
relatedEntityClass: {
type: String,
required: true,
},
relatedEntityId: {
type: Number,
required: false,
},
workflowsAvailables: {
type: Array,
required: true,
},
preventDefaultMoveToGenerate: {
type: Boolean,
required: false,
default: false,
},
goToGenerateWorkflowPayload: {
required: false,
default: {},
},
},
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
},
}
},
computed: {
countWorkflows() {
return this.workflows.length;
},
hasWorkflow() {
return this.countWorkflows > 0;
}
},
methods: {
openModal() {
this.modal.showModal = true;
},
goToGenerateWorkflow(data) {
console.log('go to generate workflow intercepted', data);
this.$emit('goToGenerateWorkflow', data);
}
},
i18n: {
messages: {
fr: {
workflow_list: "Liste des workflows associés",
workflow: " workflow associé",
workflows: " workflows associés",
}
}
}
}
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
};
},
computed: {
countWorkflows() {
return this.workflows.length;
},
hasWorkflow() {
return this.countWorkflows > 0;
},
},
methods: {
openModal() {
this.modal.showModal = true;
},
goToGenerateWorkflow(data) {
console.log("go to generate workflow intercepted", data);
this.$emit("goToGenerateWorkflow", data);
},
},
i18n: {
messages: {
fr: {
workflow_list: "Liste des workflows associés",
workflow: " workflow associé",
workflows: " workflows associés",
},
},
},
};
</script>
<style scoped></style>

View File

@ -1,12 +1,27 @@
<template>
<template v-if="props.workflowsAvailables.length >= 1">
<div v-if="countExistingWorkflows == 0 || embeddedWithinListModal" class="dropdown d-grid gap-2">
<button class="btn btn-primary dropdown-toggle" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
<div
v-if="countExistingWorkflows == 0 || embeddedWithinListModal"
class="dropdown d-grid gap-2"
>
<button
class="btn btn-primary dropdown-toggle"
type="button"
id="createWorkflowButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
Créer un workflow
</button>
<ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
<li v-for="w in props.workflowsAvailables" :key="w.name">
<button class="dropdown-item" type="button" @click.prevent="goToGenerateWorkflow($event, w.name)">{{ w.text }}</button>
<button
class="dropdown-item"
type="button"
@click.prevent="goToGenerateWorkflow($event, w.name)"
>
{{ w.text }}
</button>
</li>
</ul>
</div>
@ -20,12 +35,31 @@
{{ countExistingWorkflows }} workflows associés
</template>
</button>
<button class="btn btn-primary dropdown-toggle dropdown-toggle-split" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Liste des workflows disponibles</span>
<button
class="btn btn-primary dropdown-toggle dropdown-toggle-split"
type="button"
id="createWorkflowButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<span class="visually-hidden"
>Liste des workflows disponibles</span
>
</button>
<ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
<ul
class="dropdown-menu"
aria-labelledby="createWorkflowButton"
>
<li v-for="w in props.workflowsAvailables" :key="w.name">
<button class="dropdown-item" type="button" @click.prevent="goToGenerateWorkflow($event, w.name)">{{ w.text }}</button>
<button
class="dropdown-item"
type="button"
@click.prevent="
goToGenerateWorkflow($event, w.name)
"
>
{{ w.text }}
</button>
</li>
</ul>
</div>
@ -33,7 +67,14 @@
</template>
<template v-else>
<div v-if="countExistingWorkflows > 0" class="dropdown d-grid gap-2">
<button @click="emit('clickOpenList')" class="btn btn-primary" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
<button
@click="emit('clickOpenList')"
class="btn btn-primary"
type="button"
id="createWorkflowButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<template v-if="countExistingWorkflows === 1">
1 workflow associé
</template>
@ -46,9 +87,8 @@
</template>
<script setup lang="ts">
import {buildLinkCreate} from '../../../lib/entity-workflow/api';
import {WorkflowAvailable} from "../../../types";
import { buildLinkCreate } from "../../../lib/entity-workflow/api";
import { WorkflowAvailable } from "../../../types";
interface PickWorkflowConfig {
relatedEntityClass: string;
@ -58,7 +98,7 @@ interface PickWorkflowConfig {
* if the related entity is not specified or available, for instance when the entity is created within
* the interface and the id will be available later
*/
relatedEntityId: number|undefined;
relatedEntityId: number | undefined;
workflowsAvailables: WorkflowAvailable[];
preventDefaultMoveToGenerate: boolean;
goToGenerateWorkflowPayload: object;
@ -69,39 +109,68 @@ interface PickWorkflowConfig {
embeddedWithinListModal: boolean;
}
const props = withDefaults(defineProps<PickWorkflowConfig>(), {preventDefaultMoveToGenerate: false, goToGenerateWorkflowPayload: {}, allowCreateWorkflow: false});
const props = withDefaults(defineProps<PickWorkflowConfig>(), {
preventDefaultMoveToGenerate: false,
goToGenerateWorkflowPayload: {},
allowCreateWorkflow: false,
});
const emit = defineEmits<{
(e: 'goToGenerateWorkflow', {event: MouseEvent, workflowName: string, isLinkValid: boolean, link: string, payload: object}): void;
(e: 'clickOpenList'): void;
(
e: "goToGenerateWorkflow",
{
event: MouseEvent,
workflowName: string,
isLinkValid: boolean,
link: string,
payload: object,
},
): void;
(e: "clickOpenList"): void;
}>();
const makeLink = (workflowName: string): string => buildLinkCreate(workflowName, props.relatedEntityClass, props.relatedEntityId);
const makeLink = (workflowName: string): string =>
buildLinkCreate(
workflowName,
props.relatedEntityClass,
props.relatedEntityId,
);
const goToGenerateWorkflow = (event: MouseEvent, workflowName: string): void => {
console.log('goToGenerateWorkflow', event, workflowName);
let link = '';
const goToGenerateWorkflow = (
event: MouseEvent,
workflowName: string,
): void => {
console.log("goToGenerateWorkflow", event, workflowName);
let link = "";
let isLinkValid = false;
try {
link = makeLink(workflowName);
isLinkValid = true;
} catch (e) {
console.info("could not generate link to create workflow, maybe the relatedEntityId is not yet known", e);
console.info(
"could not generate link to create workflow, maybe the relatedEntityId is not yet known",
e,
);
}
if (!props.preventDefaultMoveToGenerate) {
window.location.assign(link);
}
emit('goToGenerateWorkflow', {event, workflowName, link, isLinkValid, payload: props.goToGenerateWorkflowPayload});
}
emit("goToGenerateWorkflow", {
event,
workflowName,
link,
isLinkValid,
payload: props.goToGenerateWorkflowPayload,
});
};
const goToDuplicateRelatedEntity = (event: MouseEvent, workflowName: string): void => {
}
const goToDuplicateRelatedEntity = (
event: MouseEvent,
workflowName: string,
): void => {};
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -1,157 +1,181 @@
<template>
<div>
<a id="evaluations"></a>
<div class="item-title" :title="evaluation.id || 'no id yet'">
<span>{{ evaluation.evaluation.title.fr }}</span>
</div>
<div>
<a id="evaluations"></a>
<div class="item-title" :title="evaluation.id || 'no id yet'">
<span>{{ evaluation.evaluation.title.fr }}</span>
</div>
<div class="item-url mt-3 mb-4" v-if="evaluation.evaluation.url">
<i class="fa fa-link fa-lg"></i>
<a :href="evaluation.evaluation.url" target="_blank">{{ evaluation.evaluation.url }}</a>
</div>
<div class="item-url mt-3 mb-4" v-if="evaluation.evaluation.url">
<i class="fa fa-link fa-lg"></i>
<a :href="evaluation.evaluation.url" target="_blank">{{
evaluation.evaluation.url
}}</a>
</div>
<div>
<form-evaluation ref="FormEvaluation" :key="evaluation.key" :evaluation="evaluation" :docAnchorId="docAnchorId"></form-evaluation>
<div>
<form-evaluation
ref="FormEvaluation"
:key="evaluation.key"
:evaluation="evaluation"
:docAnchorId="docAnchorId"
></form-evaluation>
<ul class="record_actions">
<li v-if="evaluation.workflows_availables.length > 0">
<ul class="record_actions">
<li v-if="evaluation.workflows_availables.length > 0">
<list-workflow-modal
:workflows="evaluation.workflows"
:allowCreate="true"
relatedEntityClass="Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation"
:relatedEntityId="evaluation.id"
:workflowsAvailables="evaluation.workflows_availables"
@go-to-generate-workflow="goToGenerateWorkflow"
></list-workflow-modal>
</li>
<li v-if="canDelete">
<a
class="btn btn-delete"
@click="modal.showModal = true"
:title="$t('action.delete')"
>{{ $t("delete_evaluation") }}</a
>
</li>
</ul>
</div>
<list-workflow-modal
:workflows="evaluation.workflows"
:allowCreate="true"
relatedEntityClass="Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation"
:relatedEntityId="evaluation.id"
:workflowsAvailables="evaluation.workflows_availables"
@go-to-generate-workflow="goToGenerateWorkflow"
></list-workflow-modal>
</li>
<li v-if="canDelete">
<a class="btn btn-delete" @click="modal.showModal = true" :title="$t('action.delete')">{{ $t('delete_evaluation')}}</a>
</li>
</ul>
</div>
<teleport to="body">
<modal v-if="modal.showModal" :modalDialogClass="modal.modalDialogClass" @close="modal.showModal = false">
<template v-slot:header>
<h2 class="modal-title">{{ $t('delete.sure') }}</h2>
</template>
<template v-slot:body>
<p>{{ $t('delete.sure_description') }}</p>
</template>
<template v-slot:footer>
<button class="btn btn-danger" @click="removeEvaluation(evaluation)">
{{ $t('delete.ok') }}
</button>
</template>
</modal>
</teleport>
</div>
<teleport to="body">
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template v-slot:header>
<h2 class="modal-title">{{ $t("delete.sure") }}</h2>
</template>
<template v-slot:body>
<p>{{ $t("delete.sure_description") }}</p>
</template>
<template v-slot:footer>
<button class="btn btn-danger" @click="removeEvaluation(evaluation)">
{{ $t("delete.ok") }}
</button>
</template>
</modal>
</teleport>
</div>
</template>
<script>
import FormEvaluation from './FormEvaluation.vue';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
import FormEvaluation from "./FormEvaluation.vue";
import Modal from "ChillMainAssets/vuejs/_components/Modal";
import ListWorkflowModal from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue";
import { buildLinkCreate } from "ChillMainAssets/lib/entity-workflow/api";
const i18n = {
messages: {
fr: {
no_evaluation_associated: "Aucune évaluation associée",
add_an_evaluation: "Évaluations disponibles",
evaluation_has_no_evaluation: "Aucune évaluation disponible",
startDate: "Date d'ouverture",
endDate: "Date de fin",
maxDate: "Date d'échéance",
warningInterval: "Rappel (jours)",
comment: "Note publique",
documents: "Documents",
delete: {
sure: "Êtes-vous sûr?",
sure_description: "Cette évaluation sera supprimée de cette action d'accompagnement",
ok: "Supprimer"
},
delete_evaluation: "Supprimer l'évaluation",
}
}
messages: {
fr: {
no_evaluation_associated: "Aucune évaluation associée",
add_an_evaluation: "Évaluations disponibles",
evaluation_has_no_evaluation: "Aucune évaluation disponible",
startDate: "Date d'ouverture",
endDate: "Date de fin",
maxDate: "Date d'échéance",
warningInterval: "Rappel (jours)",
comment: "Note publique",
documents: "Documents",
delete: {
sure: "Êtes-vous sûr?",
sure_description:
"Cette évaluation sera supprimée de cette action d'accompagnement",
ok: "Supprimer",
},
delete_evaluation: "Supprimer l'évaluation",
},
},
};
export default {
name: "AddEvaluation",
components: {
FormEvaluation,
Modal,
ListWorkflowModal,
},
props: ['evaluation', 'docAnchorId'],
i18n,
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md"
}
};
},
computed: {
pickedEvaluations() {
return this.$store.state.evaluationsPicked;
name: "AddEvaluation",
components: {
FormEvaluation,
Modal,
ListWorkflowModal,
},
props: ["evaluation", "docAnchorId"],
i18n,
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
canDelete() {
if (this.evaluation.workflows.length > 0) {
};
},
computed: {
pickedEvaluations() {
return this.$store.state.evaluationsPicked;
},
canDelete() {
if (this.evaluation.workflows.length > 0) {
return false;
}
for (let doc of this.evaluation.documents) {
if (doc.workflows.length > 0) {
return false;
}
for (let doc of this.evaluation.documents) {
if (doc.workflows.length > 0) {
return false;
}
}
return true;
},
},
methods: {
removeEvaluation(e) {
this.$store.commit('removeEvaluation', e);
return;
},
toggleEditEvaluation(e) {
this.$store.commit('toggleEvaluationEdit', { key: this.evaluation.key });
},
submitForm() {
this.toggleEditEvaluation();
},
goToGenerateWorkflow({event, link, workflowName}) {
const callback = (data) => {
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(e => e.key === this.evaluation.key).id;
window.location.assign(buildLinkCreate(workflowName,
'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation', evaluationId));
};
return this.$store.dispatch('submit', callback)
.catch(e => { console.log(e); throw e; });
}
}
}
return true;
},
},
methods: {
removeEvaluation(e) {
this.$store.commit("removeEvaluation", e);
return;
},
toggleEditEvaluation(e) {
this.$store.commit("toggleEvaluationEdit", { key: this.evaluation.key });
},
submitForm() {
this.toggleEditEvaluation();
},
goToGenerateWorkflow({ event, link, workflowName }) {
const callback = (data) => {
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
).id;
window.location.assign(
buildLinkCreate(
workflowName,
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
evaluationId,
),
);
};
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
},
};
</script>
<style lang="scss" scoped>
div.item-title{
.evaluation-title{
cursor: default;
&::before{
content: "";
}
}
}
div.item-url {
i {
color: unset!important;
margin-left: 1rem;
margin-right: 0.5rem;
}
}
div.item-title {
.evaluation-title {
cursor: default;
&::before {
content: "";
}
}
}
div.item-url {
i {
color: unset !important;
margin-left: 1rem;
margin-right: 0.5rem;
}
}
</style>

View File

@ -1,22 +1,35 @@
import { createStore } from 'vuex';
import { dateToISO, ISOToDate, datetimeToISO, ISOToDatetime, intervalDaysToISO, intervalISOToDays } from 'ChillMainAssets/chill/js/date';
import { findSocialActionsBySocialIssue } from 'ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js';
import { create } from 'ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js';
import { fetchResults, makeFetch } from 'ChillMainAssets/lib/api/apiMethods.ts';
import { fetchTemplates } from 'ChillDocGeneratorAssets/api/pickTemplate.js';
import { duplicate } from '../_api/accompanyingCourseWorkEvaluationDocument';
import { createStore } from "vuex";
import {
dateToISO,
ISOToDate,
datetimeToISO,
ISOToDatetime,
intervalDaysToISO,
intervalISOToDays,
} from "ChillMainAssets/chill/js/date";
import { findSocialActionsBySocialIssue } from "ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js";
import { create } from "ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js";
import { fetchResults, makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
import { fetchTemplates } from "ChillDocGeneratorAssets/api/pickTemplate.js";
import { duplicate } from "../_api/accompanyingCourseWorkEvaluationDocument";
const debug = process.env.NODE_ENV !== 'production';
const evalFQDN = encodeURIComponent("Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation");
const debug = process.env.NODE_ENV !== "production";
const evalFQDN = encodeURIComponent(
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
);
const store = createStore({
strict: debug,
state: {
work: window.accompanyingCourseWork,
startDate: window.accompanyingCourseWork.startDate !== null ?
dateToISO(new Date(window.accompanyingCourseWork.startDate.datetime)) : null,
endDate: window.accompanyingCourseWork.endDate !== null ?
dateToISO(new Date(window.accompanyingCourseWork.endDate.datetime)) : null,
startDate:
window.accompanyingCourseWork.startDate !== null
? dateToISO(new Date(window.accompanyingCourseWork.startDate.datetime))
: null,
endDate:
window.accompanyingCourseWork.endDate !== null
? dateToISO(new Date(window.accompanyingCourseWork.endDate.datetime))
: null,
note: window.accompanyingCourseWork.note,
privateComment: window.accompanyingCourseWork.privateComment,
goalsPicked: window.accompanyingCourseWork.goals,
@ -29,15 +42,17 @@ const store = createStore({
templatesAvailablesForAction: [],
templatesAvailablesForEvaluation: new Map([]),
personsPicked: window.accompanyingCourseWork.persons,
personsReachables: window.accompanyingCourseWork.accompanyingPeriod.participations.filter(p => p.endDate == null)
.map(p => p.person),
personsReachables:
window.accompanyingCourseWork.accompanyingPeriod.participations
.filter((p) => p.endDate == null)
.map((p) => p.person),
handlingThirdParty: window.accompanyingCourseWork.handlingThierParty,
thirdParties: window.accompanyingCourseWork.thirdParties,
referrers: window.accompanyingCourseWork.referrers,
isPosting: false,
errors: [],
me: null,
version: window.accompanyingCourseWork.version
version: window.accompanyingCourseWork.version,
},
getters: {
socialAction(state) {
@ -47,12 +62,12 @@ const store = createStore({
return state.resultsForAction.length > 0;
},
resultsForGoal: (state) => (goal) => {
let founds = state.resultsForGoal.filter(r => r.goalId === goal.id);
let founds = state.resultsForGoal.filter((r) => r.goalId === goal.id);
return founds === undefined ? [] : founds;
},
resultsPickedForGoal: (state) => (goal) => {
let found = state.goalsPicked.find(g => g.goal.id === goal.id);
let found = state.goalsPicked.find((g) => g.goal.id === goal.id);
return found === undefined ? [] : found.results;
},
@ -74,26 +89,38 @@ const store = createStore({
},
buildPayload(state) {
return {
type: 'accompanying_period_work',
type: "accompanying_period_work",
id: state.work.id,
version: state.version,
startDate: state.startDate === null || state.startDate === '' ? null : {
datetime: datetimeToISO(ISOToDate(state.startDate))
},
endDate: state.endDate === null || state.endDate === '' ? null : {
datetime: datetimeToISO(ISOToDate(state.endDate))
},
startDate:
state.startDate === null || state.startDate === ""
? null
: {
datetime: datetimeToISO(ISOToDate(state.startDate)),
},
endDate:
state.endDate === null || state.endDate === ""
? null
: {
datetime: datetimeToISO(ISOToDate(state.endDate)),
},
note: state.note,
privateComment: state.privateComment,
persons: state.personsPicked.map(p => ({id: p.id, type: p.type})),
handlingThierParty: state.handlingThirdParty === null ? null : {
id: state.handlingThirdParty.id,
type: state.handlingThirdParty.type
},
results: state.resultsPicked.map(r => ({id: r.id, type: r.type})),
thirdParties: state.thirdParties.map(t => ({id: t.id, type: t.type})),
referrers: state.referrers.map(t => ({id: t.id, type: t.type})),
goals: state.goalsPicked.map(g => {
persons: state.personsPicked.map((p) => ({ id: p.id, type: p.type })),
handlingThierParty:
state.handlingThirdParty === null
? null
: {
id: state.handlingThirdParty.id,
type: state.handlingThirdParty.type,
},
results: state.resultsPicked.map((r) => ({ id: r.id, type: r.type })),
thirdParties: state.thirdParties.map((t) => ({
id: t.id,
type: t.type,
})),
referrers: state.referrers.map((t) => ({ id: t.id, type: t.type })),
goals: state.goalsPicked.map((g) => {
let o = {
type: g.type,
note: g.note,
@ -101,55 +128,72 @@ const store = createStore({
type: g.goal.type,
id: g.goal.id,
},
results: g.results.map(r => ({id: r.id, type: r.type})),
results: g.results.map((r) => ({ id: r.id, type: r.type })),
};
if (g.id !== undefined) {
o.id = g.id;
}
return o;
}),
accompanyingPeriodWorkEvaluations: state.evaluationsPicked.map(e => {
accompanyingPeriodWorkEvaluations: state.evaluationsPicked.map((e) => {
let o = {
type: e.type,
key: e.key,
evaluation: {
id: e.evaluation.id,
type: e.evaluation.type
type: e.evaluation.type,
},
startDate: e.startDate === null || e.startDate === '' ? null : { datetime: datetimeToISO(ISOToDate(e.startDate)) },
endDate: e.endDate === null || e.endDate === '' ? null : { datetime: datetimeToISO(ISOToDate(e.endDate)) },
maxDate: e.maxDate === null || e.maxDate === '' ? null : { datetime: datetimeToISO(ISOToDate(e.maxDate)) },
startDate:
e.startDate === null || e.startDate === ""
? null
: { datetime: datetimeToISO(ISOToDate(e.startDate)) },
endDate:
e.endDate === null || e.endDate === ""
? null
: { datetime: datetimeToISO(ISOToDate(e.endDate)) },
maxDate:
e.maxDate === null || e.maxDate === ""
? null
: { datetime: datetimeToISO(ISOToDate(e.maxDate)) },
warningInterval: intervalDaysToISO(e.warningInterval),
timeSpent: e.timeSpent,
comment: e.comment,
documents: e.documents
documents: e.documents,
};
if (e.id !== undefined) {
o.id = e.id;
}
return o;
})
}),
};
}
},
},
mutations: {
setWhoAmiI(state, me) {
state.me = me;
state.me = me;
},
setEvaluationsPicked(state, evaluations) {
state.evaluationsPicked = evaluations.map((e, index) => {
var k = Object.assign(e, {
key: index,
editEvaluation: false,
startDate: e.startDate !== null ? dateToISO(new Date(e.startDate.datetime)) : null,
endDate: e.endDate !== null ? dateToISO(new Date(e.endDate.datetime)) : null,
maxDate: e.maxDate !== null ? dateToISO(new Date(e.maxDate.datetime)) : null,
warningInterval: e.warningInterval !== null ? intervalISOToDays(e.warningInterval) : null,
startDate:
e.startDate !== null
? dateToISO(new Date(e.startDate.datetime))
: null,
endDate:
e.endDate !== null ? dateToISO(new Date(e.endDate.datetime)) : null,
maxDate:
e.maxDate !== null ? dateToISO(new Date(e.maxDate.datetime)) : null,
warningInterval:
e.warningInterval !== null
? intervalISOToDays(e.warningInterval)
: null,
timeSpent: e.timeSpent !== null ? e.timeSpent : null,
documents: e.documents.map((d, docIndex) => {
return Object.assign(d, {
key: docIndex
key: docIndex,
});
}),
});
@ -181,28 +225,30 @@ const store = createStore({
state.resultsPicked.push(result);
},
removeResultPicked(state, result) {
state.resultsPicked = state.resultsPicked.filter(r => r.id !== result.id);
state.resultsPicked = state.resultsPicked.filter(
(r) => r.id !== result.id,
);
},
addGoal(state, goal) {
let g = {
type: "accompanying_period_work_goal",
goal: goal,
note: '',
results: []
}
const tmpIndex = () => {
let ar = state.goalsPicked.map(g => g.id),
s = Math.min(...ar);
return (s < 0) ? s : 0
note: "",
results: [],
};
g.id = tmpIndex() -1
const tmpIndex = () => {
let ar = state.goalsPicked.map((g) => g.id),
s = Math.min(...ar);
return s < 0 ? s : 0;
};
g.id = tmpIndex() - 1;
state.goalsPicked.push(g);
},
removeGoal(state, goal) {
state.goalsPicked = state.goalsPicked.filter(g => g.id !== goal.id);
state.goalsPicked = state.goalsPicked.filter((g) => g.id !== goal.id);
},
addResultForGoalPicked(state, { goal, result}) {
let found = state.goalsPicked.find(g => g.goal.id === goal.id);
addResultForGoalPicked(state, { goal, result }) {
let found = state.goalsPicked.find((g) => g.goal.id === goal.id);
if (found === undefined) {
return;
@ -211,39 +257,48 @@ const store = createStore({
found.results.push(result);
},
removeResultForGoalPicked(state, { goal, result }) {
let found = state.goalsPicked.find(g => g.goal.id === goal.id);
let found = state.goalsPicked.find((g) => g.goal.id === goal.id);
if (found === undefined) {
return;
}
found.results = found.results.filter(r => r.id !== result.id);
found.results = found.results.filter((r) => r.id !== result.id);
},
addDocument(state, payload) {
// associate version to stored object
payload.document.storedObject.currentVersion = payload.stored_object_version;
payload.document.storedObject.currentVersion =
payload.stored_object_version;
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
let evaluation = state.evaluationsPicked.find(
(e) => e.key === payload.key,
);
evaluation.documents.push(Object.assign(
payload.document, {
evaluation.documents.push(
Object.assign(payload.document, {
key: evaluation.documents.length + 1,
workflows_availables: state.work.workflows_availables_evaluation_documents,
workflows_availables:
state.work.workflows_availables_evaluation_documents,
workflows: [],
}));
}),
);
},
removeDocument(state, {key, document}) {
let evaluation = state.evaluationsPicked.find(e => e.key === key);
removeDocument(state, { key, document }) {
let evaluation = state.evaluationsPicked.find((e) => e.key === key);
if (evaluation === undefined) {
return;
}
evaluation.documents = evaluation.documents.filter(d => d.key !== document.key);
evaluation.documents = evaluation.documents.filter(
(d) => d.key !== document.key,
);
},
addDuplicatedDocument(state, {document, evaluation_key}) {
console.log('add duplicated document', document);
console.log('add duplicated dcuemnt - evaluation key', evaluation_key);
addDuplicatedDocument(state, { document, evaluation_key }) {
console.log("add duplicated document", document);
console.log("add duplicated dcuemnt - evaluation key", evaluation_key);
let evaluation = state.evaluationsPicked.find(e => e.key === evaluation_key);
let evaluation = state.evaluationsPicked.find(
(e) => e.key === evaluation_key,
);
document.key = evaluation.documents.length + 1;
evaluation.documents.splice(0, 0, document);
},
@ -255,28 +310,33 @@ const store = createStore({
* @return {void} - returns nothing.
*/
replaceDocument(state, payload) {
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
let evaluation = state.evaluationsPicked.find(
(e) => e.key === payload.key,
);
if (evaluation === undefined) {
return;
}
let doc = evaluation.documents.find(d => d.key === payload.oldDocument.key);
let doc = evaluation.documents.find(
(d) => d.key === payload.oldDocument.key,
);
if (typeof doc === 'undefined') {
console.error('doc not found');
if (typeof doc === "undefined") {
console.error("doc not found");
return;
}
doc.storedObject.currentVersion = payload.stored_object_version;
return;
let newDocument = Object.assign(
payload.document, {
key: evaluation.documents.length + 1,
workflows_availables: state.work.workflows_availables_evaluation_documents,
workflows: [],
}
let newDocument = Object.assign(payload.document, {
key: evaluation.documents.length + 1,
workflows_availables:
state.work.workflows_availables_evaluation_documents,
workflows: [],
});
evaluation.documents = evaluation.documents.map((d) =>
d.id === payload.oldDocument.id ? newDocument : d,
);
evaluation.documents = evaluation.documents.map(d => d.id === payload.oldDocument.id ? newDocument : d);
},
addEvaluation(state, evaluation) {
let e = {
@ -284,8 +344,8 @@ const store = createStore({
key: state.evaluationsPicked.length + 1,
evaluation: evaluation,
startDate: dateToISO(new Date()),
endDate: null,
maxDate: null,
endDate: null,
maxDate: null,
warningInterval: null,
timeSpent: null,
comment: "",
@ -297,46 +357,43 @@ const store = createStore({
state.evaluationsPicked.push(e);
},
removeEvaluation(state, evaluation) {
state.evaluationsPicked = state.evaluationsPicked.filter(e => e.key !== evaluation.key);
state.evaluationsPicked = state.evaluationsPicked.filter(
(e) => e.key !== evaluation.key,
);
},
setEvaluationStartDate(state, {key, date}) {
state.evaluationsPicked.find(e => e.key === key)
.startDate = date;
setEvaluationStartDate(state, { key, date }) {
state.evaluationsPicked.find((e) => e.key === key).startDate = date;
},
setEvaluationEndDate(state, {key, date}) {
console.log('commit date', date)
state.evaluationsPicked.find(e => e.key === key)
.endDate = date;
setEvaluationEndDate(state, { key, date }) {
console.log("commit date", date);
state.evaluationsPicked.find((e) => e.key === key).endDate = date;
},
setEvaluationMaxDate(state, {key, date}) {
state.evaluationsPicked.find(e => e.key === key)
.maxDate = date;
setEvaluationMaxDate(state, { key, date }) {
state.evaluationsPicked.find((e) => e.key === key).maxDate = date;
},
setEvaluationWarningInterval(state, {key, days}) {
state.evaluationsPicked.find(e => e.key === key)
.warningInterval = days;
setEvaluationWarningInterval(state, { key, days }) {
state.evaluationsPicked.find((e) => e.key === key).warningInterval = days;
},
setEvaluationTimeSpent(state, {key, time}) {
state.evaluationsPicked.find(e => e.key === key)
.timeSpent = time;
setEvaluationTimeSpent(state, { key, time }) {
state.evaluationsPicked.find((e) => e.key === key).timeSpent = time;
},
setEvaluationComment(state, {key, comment}) {
state.evaluationsPicked.find(e => e.key === key)
.comment = comment;
setEvaluationComment(state, { key, comment }) {
state.evaluationsPicked.find((e) => e.key === key).comment = comment;
},
toggleEvaluationEdit(state, {key}) {
let evaluation = state.evaluationsPicked.find(e => e.key === key);
toggleEvaluationEdit(state, { key }) {
let evaluation = state.evaluationsPicked.find((e) => e.key === key);
evaluation.editEvaluation = !evaluation.editEvaluation;
},
setTemplatesForEvaluation(state, {templates, evaluation}) {
setTemplatesForEvaluation(state, { templates, evaluation }) {
state.templatesAvailablesForEvaluation.set(evaluation.id, templates);
},
setTemplatesAvailablesForAction(state, templates) {
state.templatesAvailablesForAction = templates;
},
setPersonsPickedIds(state, ids) {
state.personsPicked = state.personsReachables
.filter(p => ids.includes(p.id))
state.personsPicked = state.personsReachables.filter((p) =>
ids.includes(p.id),
);
},
setNote(state, note) {
state.note = note;
@ -349,8 +406,8 @@ const store = createStore({
},
addThirdParties(state, thirdParties) {
// filter to remove existing thirdparties
let ids = state.thirdParties.map(t => t.id);
let unexistings = thirdParties.filter(t => !ids.includes(t.id));
let ids = state.thirdParties.map((t) => t.id);
let unexistings = thirdParties.filter((t) => !ids.includes(t.id));
for (let i in unexistings) {
state.thirdParties.push(unexistings[i]);
@ -358,27 +415,29 @@ const store = createStore({
},
updateThirdParty(state, thirdParty) {
for (let t of state.thirdParties) {
if (t.id === thirdParty.id){
state.thirdParties = state.thirdParties.filter(t => t.id !== thirdParty.id);
if (t.id === thirdParty.id) {
state.thirdParties = state.thirdParties.filter(
(t) => t.id !== thirdParty.id,
);
state.thirdParties.push(thirdParty);
}
}
},
removeThirdParty(state, thirdParty) {
state.thirdParties = state.thirdParties
.filter(t => t.id !== thirdParty.id);
state.thirdParties = state.thirdParties.filter(
(t) => t.id !== thirdParty.id,
);
},
addReferrers(state, referrers) {
let ids = state.referrers.map(t => t.id);
let unexistings = referrers.filter(t => !ids.includes(t.id));
let ids = state.referrers.map((t) => t.id);
let unexistings = referrers.filter((t) => !ids.includes(t.id));
for (let i in unexistings) {
state.referrers.push(unexistings[i]);
}
},
removeReferrer(state, user) {
state.referrers = state.referrers
.filter(u => u.id !== user.id);
state.referrers = state.referrers.filter((u) => u.id !== user.id);
},
setErrors(state, errors) {
state.errors = errors;
@ -388,22 +447,24 @@ const store = createStore({
},
updateDocumentTitle(state, payload) {
if (payload.id === 0) {
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
.documents.find(d => d.key === payload.key).title = payload.title;
state.evaluationsPicked
.find((e) => e.key === payload.evaluationKey)
.documents.find((d) => d.key === payload.key).title = payload.title;
} else {
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
.documents.find(d => d.id === payload.id).title = payload.title;
state.evaluationsPicked
.find((e) => e.key === payload.evaluationKey)
.documents.find((d) => d.id === payload.id).title = payload.title;
}
},
statusDocumentChanged(state, {newStatus, key}) {
const e = state.evaluationsPicked.find(e => e.key === key);
if (typeof e === 'undefined') {
console.error('evaluation not found for given key', {key});
statusDocumentChanged(state, { newStatus, key }) {
const e = state.evaluationsPicked.find((e) => e.key === key);
if (typeof e === "undefined") {
console.error("evaluation not found for given key", { key });
}
const doc = e.documents.find(d => d.storedObject?.id === newStatus.id);
if (typeof doc === 'undefined') {
console.error('document not found', {newStatus});
const doc = e.documents.find((d) => d.storedObject?.id === newStatus.id);
if (typeof doc === "undefined") {
console.error("document not found", { newStatus });
}
doc.storedObject.status = newStatus.status;
@ -413,165 +474,189 @@ const store = createStore({
},
actions: {
getWhoAmI({ commit }) {
let url = `/api/1.0/main/whoami.json`;
window.fetch(url)
.then(response => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving results for goal', s: response.status, b: response.body };
})
.then(data => {
commit('setWhoAmiI', data);
});
},
updateThirdParty({ commit }, payload) {
commit('updateThirdParty', payload);
},
getReachablesGoalsForAction({ getters, commit, dispatch }) {
let
socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/goal/by-social-action/${socialActionId}.json`
;
let url = `/api/1.0/main/whoami.json`;
window
.fetch(
url
).then( response => {
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving goal for social action', s: response.status, b: response.body };
}).then( data => {
for (let i in data.results) {
dispatch('getReachablesResultsForGoal', data.results[i]);
}
}).catch( errors => {
commit('addErrors', errors);
throw {
m: "Error while retriving results for goal",
s: response.status,
b: response.body,
};
})
.then((data) => {
commit("setWhoAmiI", data);
});
},
updateThirdParty({ commit }, payload) {
commit("updateThirdParty", payload);
},
getReachablesGoalsForAction({ getters, commit, dispatch }) {
let socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/goal/by-social-action/${socialActionId}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw {
m: "Error while retriving goal for social action",
s: response.status,
b: response.body,
};
})
.then((data) => {
for (let i in data.results) {
dispatch("getReachablesResultsForGoal", data.results[i]);
}
})
.catch((errors) => {
commit("addErrors", errors);
});
},
getReachablesResultsForGoal({ commit }, goal) {
let
url = `/api/1.0/person/social-work/result/by-goal/${goal.id}.json`
;
window.fetch(url)
.then(response => {
let url = `/api/1.0/person/social-work/result/by-goal/${goal.id}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving results for goal', s: response.status, b: response.body };
throw {
m: "Error while retriving results for goal",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setResultsForGoal', { goal, results: data.results });
.then((data) => {
commit("setResultsForGoal", { goal, results: data.results });
});
},
getReachablesResultsForAction({ getters, commit }) {
let
socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/result/by-social-action/${socialActionId}.json`
;
window.fetch(url)
.then(response => {
let socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/result/by-social-action/${socialActionId}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving results for social action', s: response.status, b: response.body };
throw {
m: "Error while retriving results for social action",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setResultsForAction', data.results);
.then((data) => {
commit("setResultsForAction", data.results);
});
},
getReachablesEvaluationsForAction({ getters, commit }) {
let
socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/evaluation/by-social-action/${socialActionId}.json`
;
window.fetch(url)
.then(response => {
let socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/evaluation/by-social-action/${socialActionId}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving evaluations for social action', s: response.status, b: response.body };
throw {
m: "Error while retriving evaluations for social action",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setEvaluationsForAction', data.results);
.then((data) => {
commit("setEvaluationsForAction", data.results);
});
},
addEvaluation({commit, dispatch}, evaluation) {
commit('addEvaluation', evaluation);
dispatch('fetchTemplatesAvailablesForEvaluation', evaluation);
addEvaluation({ commit, dispatch }, evaluation) {
commit("addEvaluation", evaluation);
dispatch("fetchTemplatesAvailablesForEvaluation", evaluation);
},
fetchTemplatesAvailablesForEvaluation({commit, state}, evaluation) {
fetchTemplatesAvailablesForEvaluation({ commit, state }, evaluation) {
if (!state.templatesAvailablesForEvaluation.has(evaluation.id)) {
// commit an empty array to avoid parallel fetching for same evaluation id
commit('setTemplatesForEvaluation', {templates: [], evaluation});
fetchResults(`/api/1.0/person/docgen/template/by-evaluation/${evaluation.id}.json`)
.then(templates => {
commit('setTemplatesForEvaluation', {templates, evaluation});
});
commit("setTemplatesForEvaluation", { templates: [], evaluation });
fetchResults(
`/api/1.0/person/docgen/template/by-evaluation/${evaluation.id}.json`,
).then((templates) => {
commit("setTemplatesForEvaluation", { templates, evaluation });
});
}
},
addDocument({commit}, payload) {
commit('addDocument', payload);
addDocument({ commit }, payload) {
commit("addDocument", payload);
},
async duplicateDocument({commit}, {document, evaluation_key}) {
async duplicateDocument({ commit }, { document, evaluation_key }) {
const newDoc = await duplicate(document.id);
commit('addDuplicatedDocument', {document: newDoc, evaluation_key});
commit("addDuplicatedDocument", { document: newDoc, evaluation_key });
},
removeDocument({commit}, payload) {
commit('removeDocument', payload);
removeDocument({ commit }, payload) {
commit("removeDocument", payload);
},
replaceDocument({commit}, payload) {
commit('replaceDocument', payload);
replaceDocument({ commit }, payload) {
commit("replaceDocument", payload);
},
submit({ getters, state, commit }, callback) {
let
payload = getters.buildPayload,
params = new URLSearchParams({'entity_version': state.version}),
let payload = getters.buildPayload,
params = new URLSearchParams({ entity_version: state.version }),
url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`,
errors = []
;
commit('setIsPosting', true);
errors = [];
commit("setIsPosting", true);
// console.log('the social action', payload);
return makeFetch('PUT', url, payload)
.then(data => {
if (typeof(callback) !== 'undefined') {
return makeFetch("PUT", url, payload)
.then((data) => {
if (typeof callback !== "undefined") {
return callback(data);
} else {
// console.log('payload', payload.privateComment)
// console.info('nothing to do here, bye bye');
window.location.assign(`/fr/person/accompanying-period/${state.work.accompanyingPeriod.id}/work`);
window.location.assign(
`/fr/person/accompanying-period/${state.work.accompanyingPeriod.id}/work`,
);
}
}).catch(error => {
console.log('error', error)
commit('setIsPosting', false);
})
.catch((error) => {
console.log("error", error);
commit("setIsPosting", false);
throw error;
});
},
updateDocumentTitle({commit}, payload) {
commit('updateDocumentTitle', payload)
}
}
updateDocumentTitle({ commit }, payload) {
commit("updateDocumentTitle", payload);
},
},
});
store.commit('setEvaluationsPicked', window.accompanyingCourseWork.accompanyingPeriodWorkEvaluations);
store.dispatch('getReachablesResultsForAction');
store.dispatch('getReachablesGoalsForAction');
store.dispatch('getReachablesEvaluationsForAction');
store.dispatch('getWhoAmI');
store.commit(
"setEvaluationsPicked",
window.accompanyingCourseWork.accompanyingPeriodWorkEvaluations,
);
store.dispatch("getReachablesResultsForAction");
store.dispatch("getReachablesGoalsForAction");
store.dispatch("getReachablesEvaluationsForAction");
store.dispatch("getWhoAmI");
store.state.evaluationsPicked.forEach(evaluation => {
store.dispatch('fetchTemplatesAvailablesForEvaluation', evaluation.evaluation)
store.state.evaluationsPicked.forEach((evaluation) => {
store.dispatch(
"fetchTemplatesAvailablesForEvaluation",
evaluation.evaluation,
);
});
fetchTemplates('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork')
.then(templates => {
store.commit('setTemplatesAvailablesForAction', templates);
}
)
fetchTemplates(
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork",
).then((templates) => {
store.commit("setTemplatesAvailablesForAction", templates);
});
export { store };

View File

@ -1,133 +1,131 @@
<template>
<div class="list-item" :class="{ checked: isChecked }">
<div class="list-item" :class="{ checked: isChecked }">
<label>
<div>
<input
v-bind:type="type"
v-model="selected"
name="item"
v-bind:id="item"
v-bind:value="setValueByType(item, type)"
/>
</div>
<label>
<div>
<input
v-bind:type="type"
v-model="selected"
name="item"
v-bind:id="item"
v-bind:value="setValueByType(item, type)" />
</div>
<suggestion-person
v-if="item.result.type === 'person'"
v-bind:item="item"
>
</suggestion-person>
<suggestion-person
v-if="item.result.type === 'person'"
v-bind:item="item">
</suggestion-person>
<suggestion-third-party
v-if="item.result.type === 'thirdparty'"
@newPriorSuggestion="newPriorSuggestion"
v-bind:item="item"
>
</suggestion-third-party>
<suggestion-third-party
v-if="item.result.type === 'thirdparty'"
@newPriorSuggestion="newPriorSuggestion"
v-bind:item="item">
</suggestion-third-party>
<suggestion-user v-if="item.result.type === 'user'" v-bind:item="item">
</suggestion-user>
<suggestion-user
v-if="item.result.type === 'user'"
v-bind:item="item">
</suggestion-user>
<suggestion-user-group
v-if="item.result.type === 'user_group'"
v-bind:item="item"
>
></suggestion-user-group
>
<suggestion-user-group
v-if="item.result.type === 'user_group'"
v-bind:item="item">
></suggestion-user-group>
<suggestion-household
v-if="item.result.type === 'household'"
v-bind:item="item">
</suggestion-household>
</label>
</div>
<suggestion-household
v-if="item.result.type === 'household'"
v-bind:item="item"
>
</suggestion-household>
</label>
</div>
</template>
<script>
import SuggestionPerson from './TypePerson';
import SuggestionThirdParty from './TypeThirdParty';
import SuggestionUser from './TypeUser';
import SuggestionHousehold from './TypeHousehold';
import SuggestionUserGroup from './TypeUserGroup';
import SuggestionPerson from "./TypePerson";
import SuggestionThirdParty from "./TypeThirdParty";
import SuggestionUser from "./TypeUser";
import SuggestionHousehold from "./TypeHousehold";
import SuggestionUserGroup from "./TypeUserGroup";
export default {
name: 'PersonSuggestion',
components: {
SuggestionPerson,
SuggestionThirdParty,
SuggestionUser,
SuggestionHousehold,
SuggestionUserGroup,
},
props: [
'item',
'search',
'type'
],
emits: ['updateSelected', 'newPriorSuggestion'],
computed: {
selected: {
set(value) {
//console.log('value', value);
this.$emit('updateSelected', value);
},
get() {
return this.search.selected;
}
name: "PersonSuggestion",
components: {
SuggestionPerson,
SuggestionThirdParty,
SuggestionUser,
SuggestionHousehold,
SuggestionUserGroup,
},
props: ["item", "search", "type"],
emits: ["updateSelected", "newPriorSuggestion"],
computed: {
selected: {
set(value) {
//console.log('value', value);
this.$emit("updateSelected", value);
},
isChecked() {
return (this.search.selected.indexOf(this.item) === -1) ? false : true;
get() {
return this.search.selected;
},
},
methods: {
setValueByType(value, type) {
return (type === 'radio')? [value] : value;
},
newPriorSuggestion(response) {
this.$emit('newPriorSuggestion', response)
}
}
},
isChecked() {
return this.search.selected.indexOf(this.item) === -1 ? false : true;
},
},
methods: {
setValueByType(value, type) {
return type === "radio" ? [value] : value;
},
newPriorSuggestion(response) {
this.$emit("newPriorSuggestion", response);
},
},
};
</script>
<style lang="scss">
div.results {
div.list-item {
padding: 0.4em 0.8em;
display: flex;
flex-direction: row;
&.checked {
background-color: #ececec;
border-bottom: 1px dotted #8b8b8b;
}
label {
display: inline-flex;
width: 100%;
div.container:not(.household) {
& > input {
margin-right: 0.8em;
}
> span:not(.name) {
margin-left: 0.5em;
opacity: 0.5;
font-size: 90%;
font-style: italic;
}
}
div.right_actions {
margin: 0 0 0 auto;
display: flex;
align-items: flex-end;
& > * {
margin-left: 0.5em;
align-self: baseline;
}
a.btn {
border: 1px solid lightgrey;
font-size: 70%;
padding: 4px;
}
}
}
div.results {
div.list-item {
padding: 0.4em 0.8em;
display: flex;
flex-direction: row;
&.checked {
background-color: #ececec;
border-bottom: 1px dotted #8b8b8b;
}
label {
display: inline-flex;
width: 100%;
div.container:not(.household) {
& > input {
margin-right: 0.8em;
}
> span:not(.name) {
margin-left: 0.5em;
opacity: 0.5;
font-size: 90%;
font-style: italic;
}
}
}
div.right_actions {
margin: 0 0 0 auto;
display: flex;
align-items: flex-end;
& > * {
margin-left: 0.5em;
align-self: baseline;
}
a.btn {
border: 1px solid lightgrey;
font-size: 70%;
padding: 4px;
}
}
}
}
}
</style>

View File

@ -1,6 +1,8 @@
<script setup lang="ts">
import {ResultItem, UserGroup} from "../../../../../../ChillMainBundle/Resources/public/types";
import {
ResultItem,
UserGroup,
} from "../../../../../../ChillMainBundle/Resources/public/types";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
import UserGroupRenderBox from "ChillMainAssets/vuejs/_components/Entity/UserGroupRenderBox.vue";
@ -15,16 +17,14 @@ const props = defineProps<TypeUserGroupProps>();
<template>
<div class="container user-group-container">
<div class="user-group-identification">
<user-group-render-box :user-group="props.item.result"></user-group-render-box>
<user-group-render-box
:user-group="props.item.result"
></user-group-render-box>
</div>
</div>
<div class="right_actions">
<span class="badge rounded-pill bg-user-group">
Groupe d'utilisateur
</span>
<span class="badge rounded-pill bg-user-group"> Groupe d'utilisateur </span>
</div>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,430 +1,503 @@
<template>
<div v-if="action === 'show'">
<div class="flex-table">
<person-render-box render="bloc"
:person="person"
:options="{
addInfo: true,
addEntity: false,
addAltNames: true,
addAge: true,
addId: true,
addLink: false,
hLevel: 3,
addCenter: true,
addNoData: true,
isMultiline: true
}"
:show-residential-addresses="true"
<div v-if="action === 'show'">
<div class="flex-table">
<person-render-box
render="bloc"
:person="person"
:options="{
addInfo: true,
addEntity: false,
addAltNames: true,
addAge: true,
addId: true,
addLink: false,
hLevel: 3,
addCenter: true,
addNoData: true,
isMultiline: true,
}"
:show-residential-addresses="true"
></person-render-box>
</div>
</div>
<div v-else-if="action === 'edit' || action === 'create'">
<div class="form-floating mb-3">
<input
class="form-control form-control-lg"
id="lastname"
v-model="lastName"
:placeholder="$t('person.lastname')"
@change="checkErrors"
/>
<label for="lastname">{{ $t('person.lastname') }}</label>
</div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li v-for="(qi, i) in queryItems" :key="i" @click="addQueryItem('lastName', qi)">
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
<div class="form-floating mb-3">
<input
class="form-control form-control-lg"
id="firstname"
v-model="firstName"
:placeholder="$t('person.firstname')"
@change="checkErrors"
/>
<label for="firstname">{{ $t('person.firstname') }}</label>
</div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li v-for="(qi, i) in queryItems" :key="i" @click="addQueryItem('firstName', qi)">
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
<div v-for="(a, i) in config.altNames" :key="a.key" class="form-floating mb-3">
<input
class="form-control form-control-lg"
:id="a.key"
:value="personAltNamesLabels[i]"
@input="onAltNameInput"
/>
<label :for="a.key">{{ a.labels.fr }}</label>
</div>
<!-- TODO fix placeholder if undefined
-->
<div class="form-floating mb-3">
<select
class="form-select form-select-lg"
id="gender"
v-model="gender"
>
<option selected disabled >{{ $t('person.gender.placeholder') }}</option>
<option v-for="g in config.genders" :value="g.id" :key="g.id">
{{ g.label }}
</option>
</select>
<label>{{ $t('person.gender.title') }}</label>
</div>
<div class="form-floating mb-3" v-if="showCenters && config.centers.length > 1">
<select
class="form-select form-select-lg"
id="center"
v-model="center"
>
<option selected disabled>{{ $t('person.center.placeholder') }}</option>
<option v-for="c in config.centers" :value="c" :key="c.id" >{{ c.name }}</option>
</select>
<label>{{ $t('person.center.title') }}</label>
</div>
</div>
<div class="form-floating mb-3">
<select
class="form-select form-select-lg"
id="civility"
v-model="civility"
>
<option selected disabled >{{ $t('person.civility.placeholder') }}</option>
<option v-for="c in config.civilities" :value="c.id" :key="c.id">
{{ c.name.fr }}
</option>
</select>
<label>{{ $t('person.civility.title') }}</label>
</div>
<div v-else-if="action === 'edit' || action === 'create'">
<div class="form-floating mb-3">
<input
class="form-control form-control-lg"
id="lastname"
v-model="lastName"
:placeholder="$t('person.lastname')"
@change="checkErrors"
/>
<label for="lastname">{{ $t("person.lastname") }}</label>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="birthdate"><i class="fa fa-fw fa-birthday-cake"></i></span>
<input type="date"
class="form-control form-control-lg"
id="chill_personbundle_person_birthdate"
name="chill_personbundle_person[birthdate]"
v-model="birthDate"
aria-describedby="birthdate" />
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="phonenumber"><i class="fa fa-fw fa-phone"></i></span>
<input class="form-control form-control-lg"
v-model="phonenumber"
:placeholder="$t('person.phonenumber')"
:aria-label="$t('person.phonenumber')"
aria-describedby="phonenumber" />
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="mobilenumber"><i class="fa fa-fw fa-mobile"></i></span>
<input class="form-control form-control-lg"
v-model="mobilenumber"
:placeholder="$t('person.mobilenumber')"
:aria-label="$t('person.mobilenumber')"
aria-describedby="mobilenumber" />
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="email"><i class="fa fa-fw fa-at"></i></span>
<input class="form-control form-control-lg"
v-model="email"
:placeholder="$t('person.email')"
:aria-label="$t('person.email')"
aria-describedby="email" />
</div>
<div v-if="action === 'create'" class="input-group mb-3 form-check">
<input class="form-check-input"
type='checkbox'
v-model="showAddressForm"
name='showAddressForm'/>
<label class="form-check-label">{{ $t('person.address.show_address_form') }}</label>
</div>
<div v-if="action === 'create' && showAddressFormValue" class="form-floating mb-3">
<p>{{ $t('person.address.warning') }}</p>
<add-address
:context="addAddress.context"
:options="addAddress.options"
:addressChangedCallback="submitNewAddress"
ref="addAddress">
</add-address>
</div>
<div class="alert alert-warning" v-if="errors.length">
<ul>
<li v-for="(e, i) in errors" :key="i">{{ e }}</li>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li
v-for="(qi, i) in queryItems"
:key="i"
@click="addQueryItem('lastName', qi)"
>
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
</div>
</div>
<div class="form-floating mb-3">
<input
class="form-control form-control-lg"
id="firstname"
v-model="firstName"
:placeholder="$t('person.firstname')"
@change="checkErrors"
/>
<label for="firstname">{{ $t("person.firstname") }}</label>
</div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li
v-for="(qi, i) in queryItems"
:key="i"
@click="addQueryItem('firstName', qi)"
>
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
<div
v-for="(a, i) in config.altNames"
:key="a.key"
class="form-floating mb-3"
>
<input
class="form-control form-control-lg"
:id="a.key"
:value="personAltNamesLabels[i]"
@input="onAltNameInput"
/>
<label :for="a.key">{{ a.labels.fr }}</label>
</div>
<!-- TODO fix placeholder if undefined
-->
<div class="form-floating mb-3">
<select class="form-select form-select-lg" id="gender" v-model="gender">
<option selected disabled>{{ $t("person.gender.placeholder") }}</option>
<option v-for="g in config.genders" :value="g.id" :key="g.id">
{{ g.label }}
</option>
</select>
<label>{{ $t("person.gender.title") }}</label>
</div>
<div
class="form-floating mb-3"
v-if="showCenters && config.centers.length > 1"
>
<select class="form-select form-select-lg" id="center" v-model="center">
<option selected disabled>{{ $t("person.center.placeholder") }}</option>
<option v-for="c in config.centers" :value="c" :key="c.id">
{{ c.name }}
</option>
</select>
<label>{{ $t("person.center.title") }}</label>
</div>
<div class="form-floating mb-3">
<select
class="form-select form-select-lg"
id="civility"
v-model="civility"
>
<option selected disabled>
{{ $t("person.civility.placeholder") }}
</option>
<option v-for="c in config.civilities" :value="c.id" :key="c.id">
{{ c.name.fr }}
</option>
</select>
<label>{{ $t("person.civility.title") }}</label>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="birthdate"
><i class="fa fa-fw fa-birthday-cake"></i
></span>
<input
type="date"
class="form-control form-control-lg"
id="chill_personbundle_person_birthdate"
name="chill_personbundle_person[birthdate]"
v-model="birthDate"
aria-describedby="birthdate"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="phonenumber"
><i class="fa fa-fw fa-phone"></i
></span>
<input
class="form-control form-control-lg"
v-model="phonenumber"
:placeholder="$t('person.phonenumber')"
:aria-label="$t('person.phonenumber')"
aria-describedby="phonenumber"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="mobilenumber"
><i class="fa fa-fw fa-mobile"></i
></span>
<input
class="form-control form-control-lg"
v-model="mobilenumber"
:placeholder="$t('person.mobilenumber')"
:aria-label="$t('person.mobilenumber')"
aria-describedby="mobilenumber"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="email"
><i class="fa fa-fw fa-at"></i
></span>
<input
class="form-control form-control-lg"
v-model="email"
:placeholder="$t('person.email')"
:aria-label="$t('person.email')"
aria-describedby="email"
/>
</div>
<div v-if="action === 'create'" class="input-group mb-3 form-check">
<input
class="form-check-input"
type="checkbox"
v-model="showAddressForm"
name="showAddressForm"
/>
<label class="form-check-label">{{
$t("person.address.show_address_form")
}}</label>
</div>
<div
v-if="action === 'create' && showAddressFormValue"
class="form-floating mb-3"
>
<p>{{ $t("person.address.warning") }}</p>
<add-address
:context="addAddress.context"
:options="addAddress.options"
:addressChangedCallback="submitNewAddress"
ref="addAddress"
>
</add-address>
</div>
<div class="alert alert-warning" v-if="errors.length">
<ul>
<li v-for="(e, i) in errors" :key="i">{{ e }}</li>
</ul>
</div>
</div>
</template>
<script>
import { getCentersForPersonCreation, getCivilities, getGenders, getPerson, getPersonAltNames } from '../../_api/OnTheFly';
import PersonRenderBox from '../Entity/PersonRenderBox.vue';
import {
getCentersForPersonCreation,
getCivilities,
getGenders,
getPerson,
getPersonAltNames,
} from "../../_api/OnTheFly";
import PersonRenderBox from "../Entity/PersonRenderBox.vue";
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
export default {
name: "OnTheFlyPerson",
props: ['id', 'type', 'action', 'query'],
//emits: ['createAction'],
components: {
PersonRenderBox,
AddAddress
},
data() {
return {
person: {
type: 'person',
lastName: '',
firstName: '',
altNames: [],
addressId: null,
center: null,
},
config: {
altNames: [],
civilities: [],
centers: [],
genders: []
},
showCenters: false, // NOTE: must remains false if the form is not in create mode
showAddressFormValue: false,
addAddress: {
options: {
button: {
text: { create: 'person.address.create_address' },
size: 'btn-sm'
},
title: { create: 'person.address.create_address' },
},
context: {
target: {}, // boilerplate for getting the address id
edit: false,
addressId: null,
defaults: window.addaddress
}
},
errors: []
}
},
computed: {
firstName: {
set(value) {
this.person.firstName = value;
},
get() { return this.person.firstName; }
name: "OnTheFlyPerson",
props: ["id", "type", "action", "query"],
//emits: ['createAction'],
components: {
PersonRenderBox,
AddAddress,
},
data() {
return {
person: {
type: "person",
lastName: "",
firstName: "",
altNames: [],
addressId: null,
center: null,
},
lastName: {
set(value) { this.person.lastName = value; },
get() { return this.person.lastName; }
config: {
altNames: [],
civilities: [],
centers: [],
genders: [],
},
gender: {
set(value) { this.person.gender = {id: value, type: 'chill_main_gender'}; },
get() { return this.person.gender ? this.person.gender.id : null; }
showCenters: false, // NOTE: must remains false if the form is not in create mode
showAddressFormValue: false,
addAddress: {
options: {
button: {
text: { create: "person.address.create_address" },
size: "btn-sm",
},
title: { create: "person.address.create_address" },
},
context: {
target: {}, // boilerplate for getting the address id
edit: false,
addressId: null,
defaults: window.addaddress,
},
},
civility: {
set(value) { this.person.civility = {id: value, type: 'chill_main_civility'}; },
get() { return this.person.civility ? this.person.civility.id : null; }
errors: [],
};
},
computed: {
firstName: {
set(value) {
this.person.firstName = value;
},
birthDate: {
set(value) {
if (this.person.birthdate) {
this.person.birthdate.datetime = value + "T00:00:00+0100";
} else {
this.person.birthdate = { datetime: value + "T00:00:00+0100"};
}
},
get() {
return (this.person.birthdate) ? this.person.birthdate.datetime.split('T')[0] : '';
}
get() {
return this.person.firstName;
},
phonenumber: {
set(value) { this.person.phonenumber = value; },
get() { return this.person.phonenumber; }
},
lastName: {
set(value) {
this.person.lastName = value;
},
mobilenumber: {
set(value) { this.person.mobilenumber = value; },
get() { return this.person.mobilenumber; }
get() {
return this.person.lastName;
},
email: {
set(value) { this.person.email = value; },
get() { return this.person.email; }
},
gender: {
set(value) {
this.person.gender = { id: value, type: "chill_main_gender" };
},
showAddressForm: {
set(value) { this.showAddressFormValue = value; },
get() { return this.showAddressFormValue; }
get() {
return this.person.gender ? this.person.gender.id : null;
},
center: {
set(value) {
console.log('will set center', value);
this.person.center = {id: value.id, type: value.type};
},
get() {
const center = this.config.centers.find(c => this.person.center !== null && this.person.center.id === c.id);
},
civility: {
set(value) {
this.person.civility = { id: value, type: "chill_main_civility" };
},
get() {
return this.person.civility ? this.person.civility.id : null;
},
},
birthDate: {
set(value) {
if (this.person.birthdate) {
this.person.birthdate.datetime = value + "T00:00:00+0100";
} else {
this.person.birthdate = { datetime: value + "T00:00:00+0100" };
}
},
get() {
return this.person.birthdate
? this.person.birthdate.datetime.split("T")[0]
: "";
},
},
phonenumber: {
set(value) {
this.person.phonenumber = value;
},
get() {
return this.person.phonenumber;
},
},
mobilenumber: {
set(value) {
this.person.mobilenumber = value;
},
get() {
return this.person.mobilenumber;
},
},
email: {
set(value) {
this.person.email = value;
},
get() {
return this.person.email;
},
},
showAddressForm: {
set(value) {
this.showAddressFormValue = value;
},
get() {
return this.showAddressFormValue;
},
},
center: {
set(value) {
console.log("will set center", value);
this.person.center = { id: value.id, type: value.type };
},
get() {
const center = this.config.centers.find(
(c) => this.person.center !== null && this.person.center.id === c.id,
);
console.log('center get', center);
console.log("center get", center);
return typeof center === 'undefined' ? null : center;
},
return typeof center === "undefined" ? null : center;
},
genderClass() {
switch (this.person.gender) {
case 'woman':
return 'fa-venus';
case 'man':
return 'fa-mars';
case 'both':
return 'fa-neuter';
case 'unknown':
return 'fa-genderless';
default:
return 'fa-genderless';
}
},
genderTranslation() {
switch (this.person.gender.genderTranslation) {
case 'woman':
return 'person.gender.woman';
case 'man':
return 'person.gender.man';
case 'neutral':
return 'person.gender.neutral';
case 'unknown':
return 'person.gender.unknown';
default:
return 'person.gender.unknown';
}
},
feminized() {
return (this.person.gender === 'woman')? 'e' : '';
},
personAltNamesLabels() {
return this.person.altNames.map(a => a ? a.label : '');
},
queryItems() {
return this.query ? this.query.split(' ') : null;
},
genderClass() {
switch (this.person.gender) {
case "woman":
return "fa-venus";
case "man":
return "fa-mars";
case "both":
return "fa-neuter";
case "unknown":
return "fa-genderless";
default:
return "fa-genderless";
}
},
mounted() {
getPersonAltNames()
.then(altNames => {
this.config.altNames = altNames;
});
getCivilities()
.then(civilities => {
if ('results' in civilities) {
this.config.civilities = civilities.results;
}
});
getGenders()
.then(genders => {
if ('results' in genders) {
console.log('genders', genders.results)
this.config.genders = genders.results;
}
});
if (this.action !== 'create') {
this.loadData();
} else {
// console.log('show centers', this.showCenters);
getCentersForPersonCreation()
.then(params => {
this.config.centers = params.centers.filter(c => c.isActive);
this.showCenters = params.showCenters;
// console.log('centers', this.config.centers)
// console.log('show centers inside', this.showCenters);
if (this.showCenters && this.config.centers.length === 1) {
this.person.center = this.config.centers[0];
}
});
},
genderTranslation() {
switch (this.person.gender.genderTranslation) {
case "woman":
return "person.gender.woman";
case "man":
return "person.gender.man";
case "neutral":
return "person.gender.neutral";
case "unknown":
return "person.gender.unknown";
default:
return "person.gender.unknown";
}
},
methods: {
checkErrors(e) {
this.errors = [];
if (this.person.lastName === "") {
this.errors.push("Le nom ne doit pas être vide.");
}
if (this.person.firstName === "") {
this.errors.push("Le prénom ne doit pas être vide.");
}
if (!this.person.gender) {
this.errors.push("Le genre doit être renseigné");
}
if (this.showCenters && this.person.center === null) {
this.errors.push("Le centre doit être renseigné");
}
},
loadData() {
getPerson(this.id)
.then(person => new Promise((resolve, reject) => {
this.person = person;
//console.log('get person', this.person);
resolve();
}));
},
onAltNameInput(event) {
const key = event.target.id;
const label = event.target.value;
let updateAltNames = this.person.altNames.filter((a) => a.key !== key);
updateAltNames.push(
{'key': key, 'label': label}
)
this.person.altNames = updateAltNames;
},
addQueryItem(field, queryItem) {
switch (field) {
case 'lastName':
this.person.lastName = this.person.lastName ? this.person.lastName += ` ${queryItem}` : queryItem;
break;
case 'firstName':
this.person.firstName = this.person.firstName ? this.person.firstName += ` ${queryItem}` : queryItem;
break;
}
},
submitNewAddress(payload) {
this.person.addressId = payload.addressId;
},
feminized() {
return this.person.gender === "woman" ? "e" : "";
},
personAltNamesLabels() {
return this.person.altNames.map((a) => (a ? a.label : ""));
},
queryItems() {
return this.query ? this.query.split(" ") : null;
},
},
mounted() {
getPersonAltNames().then((altNames) => {
this.config.altNames = altNames;
});
getCivilities().then((civilities) => {
if ("results" in civilities) {
this.config.civilities = civilities.results;
}
}
}
});
getGenders().then((genders) => {
if ("results" in genders) {
console.log("genders", genders.results);
this.config.genders = genders.results;
}
});
if (this.action !== "create") {
this.loadData();
} else {
// console.log('show centers', this.showCenters);
getCentersForPersonCreation().then((params) => {
this.config.centers = params.centers.filter((c) => c.isActive);
this.showCenters = params.showCenters;
// console.log('centers', this.config.centers)
// console.log('show centers inside', this.showCenters);
if (this.showCenters && this.config.centers.length === 1) {
this.person.center = this.config.centers[0];
}
});
}
},
methods: {
checkErrors(e) {
this.errors = [];
if (this.person.lastName === "") {
this.errors.push("Le nom ne doit pas être vide.");
}
if (this.person.firstName === "") {
this.errors.push("Le prénom ne doit pas être vide.");
}
if (!this.person.gender) {
this.errors.push("Le genre doit être renseigné");
}
if (this.showCenters && this.person.center === null) {
this.errors.push("Le centre doit être renseigné");
}
},
loadData() {
getPerson(this.id).then(
(person) =>
new Promise((resolve, reject) => {
this.person = person;
//console.log('get person', this.person);
resolve();
}),
);
},
onAltNameInput(event) {
const key = event.target.id;
const label = event.target.value;
let updateAltNames = this.person.altNames.filter((a) => a.key !== key);
updateAltNames.push({ key: key, label: label });
this.person.altNames = updateAltNames;
},
addQueryItem(field, queryItem) {
switch (field) {
case "lastName":
this.person.lastName = this.person.lastName
? (this.person.lastName += ` ${queryItem}`)
: queryItem;
break;
case "firstName":
this.person.firstName = this.person.firstName
? (this.person.firstName += ` ${queryItem}`)
: queryItem;
break;
}
},
submitNewAddress(payload) {
this.person.addressId = payload.addressId;
},
},
};
</script>
<style lang="scss" scoped>
div.flex-table {
div.item-bloc {
div.item-row {
div.item-col:last-child {
justify-content: flex-start;
}
div.item-bloc {
div.item-row {
div.item-col:last-child {
justify-content: flex-start;
}
}
}
}
}
dl {
dd {
margin-left: 1em;
}
dd {
margin-left: 1em;
}
}
div.form-check {
label {
margin-left: 0.5em!important;
}
label {
margin-left: 0.5em !important;
}
}
</style>

View File

@ -1,6 +1,6 @@
const Encore = require('@symfony/webpack-encore');
const { resolve, parse } = require('path');
const { readdir } = require('fs').promises;
const Encore = require("@symfony/webpack-encore");
const { resolve, parse } = require("path");
const { readdir } = require("fs").promises;
/**
* get the file names inside given directory recursively, limiting to
@ -10,20 +10,20 @@ const { readdir } = require('fs').promises;
* @param int depth the maximum depth to look into
*/
async function* getFiles(dir, depth, ignored) {
const dirents = await readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
const res = resolve(dir, dirent.name);
if (dirent.isDirectory()) {
if (depth > 0) {
yield* getFiles(res, depth - 1, ignored);
}
} else if (ignored.includes(res)) {
continue;
} else {
yield res;
}
const dirents = await readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
const res = resolve(dir, dirent.name);
if (dirent.isDirectory()) {
if (depth > 0) {
yield* getFiles(res, depth - 1, ignored);
}
} else if (ignored.includes(res)) {
continue;
} else {
yield res;
}
};
}
}
/**
* populate the config of encore in directories inside `'./src'` and
@ -38,88 +38,84 @@ async function* getFiles(dir, depth, ignored) {
*
*/
async function populateConfig(Encore, chillEntries) {
// chill-main contains some bootstrap that must be loaded first.
// we register them first and, then, store this chill.webpack.config.js file
// into `toIgnore`, ignoring it when we loop on other folders.
let
toIgnore = [];
// chill-main contains some bootstrap that must be loaded first.
// we register them first and, then, store this chill.webpack.config.js file
// into `toIgnore`, ignoring it when we loop on other folders.
let toIgnore = [];
// loop into chill main
for await (const f of getFiles('./src/Bundle/ChillMainBundle/', 1, [])) {
let filename = parse(f).base;
if (filename === 'chill.webpack.config.js') {
configure = require(f);
configure(Encore, chillEntries);
toIgnore.push(f);
}
// loop into chill main
for await (const f of getFiles("./src/Bundle/ChillMainBundle/", 1, [])) {
let filename = parse(f).base;
if (filename === "chill.webpack.config.js") {
configure = require(f);
configure(Encore, chillEntries);
toIgnore.push(f);
}
}
// loop into other chill bundles
for await (const f of getFiles('./src/Bundle', 2, toIgnore)) {
let filename = parse(f).base;
if (filename === 'chill.webpack.config.js') {
configure = require(f);
configure(Encore, chillEntries);
}
// loop into other chill bundles
for await (const f of getFiles("./src/Bundle", 2, toIgnore)) {
let filename = parse(f).base;
if (filename === "chill.webpack.config.js") {
configure = require(f);
configure(Encore, chillEntries);
}
};
}
}
// export the final configuration
module.exports = (async () => {
// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || "dev");
}
// basic encore configuration
Encore.setOutputPath("public/build/")
.setPublicPath("/build")
.enableSassLoader()
.enableVueLoader(() => {}, {
version: 3,
})
.enableTypeScriptLoader(function (tsConfig) {
tsConfig.appendTsSuffixTo = [/\.vue$/];
tsConfig.appendTsxSuffixTo = [/\.vue$/];
// temporary fix for https://github.com/vuejs/vue-loader/issues/1915 and https://github.com/vuejs/core/issues/2855
tsConfig.compilerOptions = { strict: !Encore.isProduction() };
tsConfig.silent = false;
})
//.enableForkedTypeScriptTypesChecking()
.autoProvidejQuery()
.enableSourceMaps(!Encore.isProduction())
.cleanupOutputBeforeBuild()
//.enableBuildNotifications()
.enableVersioning()
.enableSingleRuntimeChunk()
.splitEntryChunks();
// added when upgrading to symfony 5.4
// enables and configure @babel/preset-env polyfills
//.configureBabelPresetEnv((config) => {
// config.useBuiltIns = 'usage';
// config.corejs = '3.23';
//})
//.addLoader({ test: /\.pdf$/, loader: 'file-loader', options: { name: '[name]_[hash].[ext]', outputPath: 'pdf/' } })
// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
// basic encore configuration
Encore
.setOutputPath('public/build/')
.setPublicPath('/build')
.enableSassLoader()
.enableVueLoader(() => {}, {
version: 3
})
.enableTypeScriptLoader(function (tsConfig){
tsConfig.appendTsSuffixTo = [/\.vue$/];
tsConfig.appendTsxSuffixTo = [/\.vue$/];
// temporary fix for https://github.com/vuejs/vue-loader/issues/1915 and https://github.com/vuejs/core/issues/2855
tsConfig.compilerOptions = {strict: !Encore.isProduction()};
tsConfig.silent = false;
})
//.enableForkedTypeScriptTypesChecking()
.autoProvidejQuery()
.enableSourceMaps(!Encore.isProduction())
.cleanupOutputBeforeBuild()
//.enableBuildNotifications()
.enableVersioning()
.enableSingleRuntimeChunk()
.splitEntryChunks()
// added when upgrading to symfony 5.4
// enables and configure @babel/preset-env polyfills
//.configureBabelPresetEnv((config) => {
// config.useBuiltIns = 'usage';
// config.corejs = '3.23';
//})
//.addLoader({ test: /\.pdf$/, loader: 'file-loader', options: { name: '[name]_[hash].[ext]', outputPath: 'pdf/' } })
;
// populate config with chill entries
let chillEntries = [];
await populateConfig(Encore, chillEntries);
// configure Babel
// .configureBabel((config) => {
// config.plugins.push('@babel/a-babel-plugin');
// })
// populate config with chill entries
let chillEntries = [];
await populateConfig(Encore, chillEntries);
// configure Babel
// .configureBabel((config) => {
// config.plugins.push('@babel/a-babel-plugin');
// })
//getting the encore config and appending chill entries
config = Encore.getWebpackConfig();
config.entry.chill = chillEntries;
//getting the encore config and appending chill entries
config = Encore.getWebpackConfig();
config.entry.chill = chillEntries;
if (!Encore.isProduction()) {
console.log(config);
config.devtool = "eval-source-map";
}
if (!Encore.isProduction()) {
console.log(config);
config.devtool = 'eval-source-map';
}
return config;
return config;
})();