Compare commits

...

31 Commits

Author SHA1 Message Date
Boris Waaub
8ae48015b1 Correction du type dans la définition du modèle pour le champ de valeur dans CommentEditor.vue 2026-02-04 17:04:57 +01:00
Boris Waaub
7e59cf02e1 Refactor CommentEditor.vue to use enum for editor modes and improve type safety 2026-02-04 16:57:35 +01:00
Boris Waaub
af74fd1fd8 Ajout de la limite de mémoire pour Composer et nettoyage du cache avant l'installation, suppression de la construction dans le job vue-tsc 2026-02-04 16:50:48 +01:00
Boris Waaub
d14c88deae Ajout de la génération du rapport vue-tsc dans le job de tests et correction de l'ordre des commandes 2026-02-04 16:34:37 +01:00
Boris Waaub
b3667b797f Mise à jour du cache de build pour inclure le répertoire var et ajout de la commande de nettoyage du cache dans le job vue-tsc 2026-02-04 16:25:36 +01:00
Boris Waaub
8b129417df Ajout de dépendances au job de build pour les étapes de tests et mise à jour du cache pour inclure les traductions 2026-02-04 15:56:16 +01:00
Boris Waaub
d762e999a2 Correction de la définition du modèle dans CommentEditor.vue et mise à jour de la configuration du pipeline CI pour inclure le rapport vue-tsc 2026-02-04 15:39:06 +01:00
Boris Waaub
b8f3b64f6d Ajout de l'affichage du rapport vue-tsc dans le pipeline de lint 2026-02-04 15:20:53 +01:00
Boris Waaub
203a0d2264 FIX: Rector 2026-02-04 15:12:41 +01:00
Boris Waaub
c66105fb67 FIX: es-lint 2026-02-04 15:03:58 +01:00
Boris Waaub
701dd44169 Nettoyage des imports inutilisés dans PersonsSelectorComponent.vue et correction de la gestion des valeurs indéfinies dans PreviousTicketsComponent.vue 2026-02-04 14:51:38 +01:00
Boris Waaub
915f4292da Nettoyage des imports inutilisés dans AddresseeSelectorComponent.vue et ajout d'une condition v-if pour le rendu du CommentEditor dans CommentEditorComponent.vue 2026-02-04 14:50:13 +01:00
Boris Waaub
23369197e7 Correction des types et amélioration de la gestion des erreurs dans les composants ThirdParty et ThirdPartyEdit 2026-02-04 14:48:33 +01:00
Boris Waaub
454aad7ed1 Nettoyage des imports inutilisés dans plusieurs composants Vue pour améliorer la lisibilité du code et gestion des valeurs nulles dans PersonRenderBox.vue. 2026-02-04 14:36:07 +01:00
Boris Waaub
6e3c3c68d2 Nettoyage des imports dans plusieurs composants Vue pour améliorer la lisibilité du code. 2026-02-04 12:06:43 +01:00
Boris Waaub
22088022f6 Ajout de conditions v-if pour afficher les dates de début et de fin uniquement si elles sont présentes dans AccompanyingPeriodWorkEvaluationItem.vue 2026-02-04 12:00:05 +01:00
Boris Waaub
d5811cc4af Correction de la définition des événements et amélioration de la condition d'affichage dans GenerateButton.vue 2026-02-04 11:58:39 +01:00
Boris Waaub
79e1300acf Nettoyage des imports dans PickEntity.vue : suppression des imports inutilisés pour améliorer la lisibilité du code. 2026-02-04 11:56:09 +01:00
Boris Waaub
3bc54f45b7 Ajout de la gestion des liens davLink et davLinkExpiration en tant que propriétés optionnelles et mise à jour de la structure du template dans App.vue pour intégrer WaitingScreen. 2026-02-04 11:55:38 +01:00
Boris Waaub
1bc370fc88 Ajout de la condition v-if pour afficher le masque modal uniquement lorsque props.show est vrai et amélioration des types dans les définitions de slots. 2026-02-04 11:52:26 +01:00
Boris Waaub
5dd031f0b4 Refactor CommentEditor and PickWorkflow components: update template structure, enhance default values, and improve type definitions. 2026-02-04 11:50:12 +01:00
Boris Waaub
9208be903c Fix null reference errors in AddressDetails components by adding optional chaining to addressReference properties. 2026-02-04 11:50:00 +01:00
Boris Waaub
93929a420e Merge branch 'ticket-app-master' into 2101-fix-vue-tsc-errors 2026-02-03 16:53:51 +01:00
Boris Waaub
0471337888 Refactor OnTheFly and PersonEdit components: remove unused imports, enhance type safety, and add unique keys for v-for loops. 2026-02-03 16:51:35 +01:00
Boris Waaub
1c30bcd906 Refactor HistoryButton and HistoryButtonModal components: streamline template structure, enhance type handling, and improve event emission for version restoration. 2026-02-03 15:33:19 +01:00
Boris Waaub
e97c740a75 Refactor Vue components: update DropFile and DropFileWidget templates for clarity; enhance type definitions in FileIcon and types/index.ts; fix event emit structure in DropFileModal. 2026-02-03 15:01:09 +01:00
Boris Waaub
307200c5f4 Améliore les types et la gestion des propriétés dans les composants Vue :
- Modifie les types des propriétés dans DownloadButton.vue pour gérer les versions d'objet.
- Corrige les types de davLink et davLinkExpiration dans DocumentActionButtonsGroup.vue.
- Réorganise l'interface DesktopEditButtonConfig pour une meilleure clarté.
- Ajuste l'extension de fichier dans DownloadButton.vue pour éviter les erreurs de type.
2026-02-03 14:42:35 +01:00
Boris Waaub
6852dcd0f0 Refactor Vue components: streamline Answer.vue with setup syntax and remove redundant i18n object; update CalendarActive.vue template for clarity. 2026-02-03 14:24:46 +01:00
Boris Waaub
c19e6fea40 TS2322: Type '(_: any) => void' is not assignable to type '() => any'. 2026-02-03 12:26:40 +01:00
Boris Waaub
4eda457ef2 Type 'string | null' is not assignable to type 'PropertyKey | undefined'. 2026-02-03 12:26:00 +01:00
Boris Waaub
b342483c2e error TS2345: Argument of type 'string' is not assignable to parameter of type '"pending" | "accepted" | "declined" | "tentative"'. 2026-02-03 12:16:15 +01:00
49 changed files with 578 additions and 575 deletions

View File

@@ -97,10 +97,12 @@ build:
stage: Composer install
image: chill/base-image:8.3-edge
variables:
COMPOSER_MEMORY_LIMIT: 3G
before_script:
- composer config -g cache-dir "$(pwd)/.cache"
script:
- composer install --optimize-autoloader --no-ansi --no-interaction --no-progress
- php bin/console cache:clear
cache:
paths:
- .cache/
@@ -108,12 +110,15 @@ build:
expire_in: 1 day
paths:
- vendor/
- var/
code_style:
stage: Tests
image: chill/base-image:8.3-edge
script:
- php-cs-fixer fix --dry-run -v --show-progress=none
dependencies:
- build
cache:
paths:
- .cache/
@@ -131,6 +136,8 @@ phpstan_tests:
- bin/console cache:clear --env=dev
script:
- composer exec phpstan -- analyze --memory-limit=3G
dependencies:
- build
cache:
paths:
- .cache/
@@ -146,6 +153,8 @@ rector_tests:
- bin/console cache:clear --env=dev
script:
- composer exec rector -- process --dry-run
dependencies:
- build
cache:
paths:
- .cache/
@@ -164,16 +173,37 @@ lint:
script:
- yarn install --ignore-optional
- npx eslint-baseline "src/**/*.{js,ts,vue}"
dependencies:
- build
cache:
paths:
- node_modules/
artifacts:
expire_in: 1 day
paths:
- vendor/
vue_tsc:
stage: Tests
image: node:20-alpine
before_script:
- apk add --no-cache python3 make g++ py3-setuptools
- export PYTHON="$(which python3)"
- export PATH="./node_modules/.bin:$PATH"
script:
- yarn install --ignore-optional
- yarn vue-tsc --noEmit > vue-tsc-report.txt 2>&1 || true
- cat vue-tsc-report.txt
- grep -q "error" vue-tsc-report.txt && exit 2 || exit 0
dependencies:
- build
cache:
paths:
- node_modules/
artifacts:
expire_in: 1 day
paths:
- vue-tsc-report.txt
cache:
paths:
- node_modules/
---
# psalm_tests:
# stage: Tests
# image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
@@ -199,6 +229,8 @@ unit_tests:
- php bin/console doctrine:fixtures:load -n --env=test
script:
- composer exec phpunit -- --colors=never --exclude-group dbIntensive,openstack-integration
dependencies:
- build
artifacts:
expire_in: 1 day
paths:

View File

@@ -71,4 +71,11 @@ export function isEventInputCalendarRange(
return typeof toBeDetermined.is === "string" && toBeDetermined.is === "range";
}
export enum AnswerStatus {
ACCEPTED = "accepted",
DECLINED = "declined",
PENDING = "pending",
TENTATIVE = "tentative",
}
export {};

View File

@@ -7,7 +7,7 @@
<i v-else-if="invite.status === 'declined'" class="fa fa-times" />
<i v-else-if="invite.status === 'pending'" class="fa fa-question-o" />
<i v-else-if="invite.status === 'tentative'" class="fa fa-question" />
<span v-else="">{{ invite.status }}</span>
<span v-else>{{ invite.status }}</span>
</template>
</span>
<span class="form-check-inline form-switch">
@@ -42,8 +42,6 @@
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "CalendarActive",
props: {

View File

@@ -24,6 +24,14 @@ const appMessages = {
list_three_days: "Liste 3 jours",
current_selected: "Rendez-vous fixé",
main_user: "Utilisateur principal",
Give_an_answer: "Répondre",
Accepted: "Accepté",
Declined: "Refusé",
Tentative: "Accepté provisoirement",
Accept: "Accepter",
Decline: "Refuser",
Tentatively_accept: "Accepter provisoirement",
Set_pending: "Ne pas répondre",
},
};

View File

@@ -47,77 +47,38 @@
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from "vue";
<script lang="ts" setup>
import { AnswerStatus } from "../../types";
const ACCEPTED = "accepted";
const DECLINED = "declined";
const PENDING = "pending";
const TENTATIVELY_ACCEPTED = "tentative";
const props = defineProps<{
calendarId: number;
status: AnswerStatus;
}>();
const i18n = {
messages: {
fr: {
Give_an_answer: "Répondre",
Accepted: "Accepté",
Declined: "Refusé",
Tentative: "Accepté provisoirement",
Accept: "Accepter",
Decline: "Refuser",
Tentatively_accept: "Accepter provisoirement",
Set_pending: "Ne pas répondre",
},
},
const emit =
defineEmits<(e: "statusChanged", newStatus: AnswerStatus) => void>();
const Statuses = {
ACCEPTED: AnswerStatus.ACCEPTED,
DECLINED: AnswerStatus.DECLINED,
PENDING: AnswerStatus.PENDING,
TENTATIVELY_ACCEPTED: AnswerStatus.TENTATIVE,
};
export default defineComponent({
name: "Answer",
i18n,
props: {
calendarId: { type: Number, required: true },
status: {
type: String as PropType<
"accepted" | "declined" | "pending" | "tentative"
>,
required: true,
},
},
emits: {
statusChanged(payload: "accepted" | "declined" | "pending" | "tentative") {
return true;
},
},
data() {
return {
Statuses: {
ACCEPTED,
DECLINED,
PENDING,
TENTATIVELY_ACCEPTED,
},
};
},
methods: {
changeStatus: function (
newStatus: "accepted" | "declined" | "pending" | "tentative",
) {
console.log("changeStatus", newStatus);
const url = `/api/1.0/calendar/calendar/${this.$props.calendarId}/answer/${newStatus}.json`;
window
.fetch(url, {
method: "POST",
})
.then((r: Response) => {
if (!r.ok) {
console.error("could not confirm answer", newStatus);
return;
}
console.log("answer sent", newStatus);
this.$emit("statusChanged", newStatus);
});
},
},
});
function changeStatus(newStatus: AnswerStatus) {
const url = `/api/1.0/calendar/calendar/${props.calendarId}/answer/${newStatus}.json`;
window
.fetch(url, {
method: "POST",
})
.then((r: Response) => {
if (!r.ok) {
console.error("could not confirm answer", newStatus);
return;
}
emit("statusChanged", newStatus);
});
}
</script>
<style scoped></style>

View File

@@ -146,7 +146,11 @@
id="copyFromWeek"
class="form-select"
>
<option v-for="w in lastWeeks" :value="w.value" :key="w.value">
<option
v-for="w in lastWeeks"
:value="w.value"
:key="w.value || ''"
>
{{ w.text }}
</option>
</select>
@@ -156,7 +160,11 @@
</div>
<div class="col-xs-12 col-sm-3 col-md-3">
<select v-model="copyToWeek" id="copyToWeek" class="form-select">
<option v-for="w in nextWeeks" :value="w.value" :key="w.value">
<option
v-for="w in nextWeeks"
:value="w.value"
:key="w.value || ''"
>
{{ w.text }}
</option>
</select>

View File

@@ -74,12 +74,12 @@ const saveAndClose = function (e: Event): void {
location: location.value,
calendarRangeId: calendarRangeId.value,
})
.then((_) => {
.then(() => {
showModal.value = false;
});
};
const closeModal = function (_: any): void {
const closeModal = function (): void {
showModal.value = false;
};

View File

@@ -2,12 +2,11 @@ import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
import DocumentActionButtonsGroup from "../../vuejs/DocumentActionButtonsGroup.vue";
import { createApp } from "vue";
import { StoredObject, StoredObjectStatusChange } from "../../types";
import { is_object_ready } from "../../vuejs/StoredObjectButton/helpers";
import ToastPlugin from "vue-toast-notification";
const i18n = _createI18n({});
window.addEventListener("DOMContentLoaded", function (e) {
window.addEventListener("DOMContentLoaded", function () {
document
.querySelectorAll<HTMLDivElement>("div[data-download-buttons]")
.forEach((el) => {

View File

@@ -9,6 +9,7 @@ export interface StoredObject {
uuid: string;
prefix: string;
status: StoredObjectStatus;
type: string;
currentVersion:
| null
| StoredObjectVersionCreated

View File

@@ -26,8 +26,8 @@
<li v-if="isEditableOnDesktop">
<desktop-edit-button
:classes="{ 'dropdown-item': true }"
:edit-link="props.davLink"
:expiration-link="props.davLinkExpiration"
:edit-link="props.davLink ?? ''"
:expiration-link="props.davLinkExpiration ?? 0"
></desktop-edit-button>
</li>
<li v-if="isConvertibleToPdf">
@@ -75,7 +75,6 @@ import {
import {
StoredObject,
StoredObjectStatusChange,
StoredObjectVersion,
WopiEditButtonExecutableBeforeLeaveFunction,
} from "../types";
import DesktopEditButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DesktopEditButton.vue";
@@ -206,10 +205,6 @@ const checkForReady = function (): 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);

View File

@@ -1,3 +1,35 @@
<template>
<div class="drop-file">
<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>
<!-- 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>
</div>
<div v-else class="waiting">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
</div>
</template>
<script setup lang="ts">
import { StoredObject, StoredObjectVersionCreated } from "../../types";
import {
@@ -9,24 +41,23 @@ import { computed, ref, Ref } from "vue";
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
interface DropFileConfig {
existingDoc?: StoredObject;
existingDoc: StoredObject | null;
}
const props = withDefaults(defineProps<DropFileConfig>(), {
existingDoc: null,
});
const emit =
defineEmits<
(
e: "addDocument",
{
stored_object_version: StoredObjectVersionCreated,
stored_object: StoredObject,
file_name: string,
},
) => void
>();
const emit = defineEmits<
(
e: "addDocument",
payload: {
stored_object_version: StoredObjectVersionCreated;
stored_object: StoredObject;
file_name: string;
},
) => void
>();
const is_dragging: Ref<boolean> = ref(false);
const uploading: Ref<boolean> = ref(false);
@@ -134,38 +165,6 @@ const handleFile = async (file: File): Promise<void> => {
};
</script>
<template>
<div class="drop-file">
<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>
<!-- 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>
</div>
<div v-else class="waiting">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
</div>
</template>
<style scoped lang="scss">
.drop-file {
width: 100%;

View File

@@ -18,10 +18,10 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
const emit = defineEmits<{
(
e: "addDocument",
{
stored_object: StoredObject,
stored_object_version: StoredObjectVersion,
file_name: string,
payload: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
file_name: string;
},
): void;
(e: "removeDocument"): void;

View File

@@ -1,6 +1,34 @@
<template>
<div>
<drop-file
:existingDoc="props.existingDoc ?? null"
@addDocument="onAddDocument"
></drop-file>
<ul class="record_actions">
<li v-if="props?.existingDoc">
<document-action-buttons-group
:stored-object="props.existingDoc"
:can-edit="props.existingDoc?.status === 'ready'"
:can-download="true"
:dav-link="dav_link_href ?? ''"
:dav-link-expiration="dav_link_expiration ?? 0"
/>
</li>
<li>
<button
v-if="allowRemove"
class="btn btn-delete"
@click="onRemoveDocument($event)"
></button>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { StoredObject, StoredObjectVersion } from "../../types";
import { computed, ref, Ref } from "vue";
import { computed } from "vue";
import DropFile from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFile.vue";
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
@@ -16,19 +44,15 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
const emit = defineEmits<{
(
e: "addDocument",
{
stored_object: StoredObject,
stored_object_version: StoredObjectVersion,
file_name: string,
payload: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
file_name: string;
},
): void;
(e: "removeDocument"): void;
}>();
const has_existing_doc = computed<boolean>(() => {
return props.existingDoc !== undefined && props.existingDoc !== null;
});
const dav_link_expiration = computed<number | undefined>(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return undefined;
@@ -69,33 +93,4 @@ const onRemoveDocument = (e: Event): void => {
emit("removeDocument");
};
</script>
<template>
<div>
<drop-file
:existingDoc="props.existingDoc"
@addDocument="onAddDocument"
></drop-file>
<ul class="record_actions">
<li v-if="has_existing_doc">
<document-action-buttons-group
:stored-object="props.existingDoc"
:can-edit="props.existingDoc?.status === 'ready'"
:can-download="true"
:dav-link="dav_link_href"
:dav-link-expiration="dav_link_expiration"
/>
</li>
<li>
<button
v-if="allowRemove"
class="btn btn-delete"
@click="onRemoveDocument($event)"
></button>
</li>
</ul>
</div>
</template>
<style scoped lang="scss"></style>

View File

@@ -1,11 +1,3 @@
<script setup lang="ts">
interface FileIconConfig {
type: string;
}
const props = defineProps<FileIconConfig>();
</script>
<template>
<i class="fa fa-file-pdf-o" v-if="props.type === 'application/pdf'"></i>
<i
@@ -43,4 +35,12 @@ const props = defineProps<FileIconConfig>();
<i class="fa fa-file-code-o" v-else></i>
</template>
<script setup lang="ts">
interface FileIconConfig {
type: string;
}
const props = defineProps<FileIconConfig>();
</script>
<style scoped lang="scss"></style>

View File

@@ -1,42 +1,3 @@
<script setup lang="ts">
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import { computed, reactive } from "vue";
export interface DesktopEditButtonConfig {
editLink: null;
classes: Record<string, boolean>;
expirationLink: number | Date;
}
interface DesktopEditButtonState {
modalOpened: boolean;
}
const state: DesktopEditButtonState = reactive({ modalOpened: false });
const props = defineProps<DesktopEditButtonConfig>();
const buildCommand = computed<string>(
() => "vnd.libreoffice.command:ofe|u|" + props.editLink,
);
const editionUntilFormatted = computed<string>(() => {
let d;
if (props.expirationLink instanceof Date) {
d = props.expirationLink;
} else {
d = new Date(props.expirationLink * 1000);
}
console.log(props.expirationLink);
return new Intl.DateTimeFormat(undefined, {
dateStyle: "long",
timeStyle: "medium",
}).format(d);
});
</script>
<template>
<teleport to="body">
<modal v-if="state.modalOpened" @close="state.modalOpened = false">
@@ -90,3 +51,41 @@ i.fa::before {
color: var(--bs-dropdown-link-hover-color);
}
</style>
<script setup lang="ts">
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import { computed, reactive } from "vue";
export interface DesktopEditButtonConfig {
editLink: string;
classes: Record<string, boolean>;
expirationLink: number | Date;
}
interface DesktopEditButtonState {
modalOpened: boolean;
}
const state: DesktopEditButtonState = reactive({ modalOpened: false });
const props = defineProps<DesktopEditButtonConfig>();
const buildCommand = computed<string>(
() => "vnd.libreoffice.command:ofe|u|" + props.editLink,
);
const editionUntilFormatted = computed<string>(() => {
let d;
if (props.expirationLink instanceof Date) {
d = props.expirationLink;
} else {
d = new Date(props.expirationLink * 1000);
}
return new Intl.DateTimeFormat(undefined, {
dateStyle: "long",
timeStyle: "medium",
}).format(d);
});
</script>

View File

@@ -12,7 +12,7 @@
v-else
:class="props.classes"
target="_blank"
:type="props.atVersion.type"
:type="props.atVersion?.type"
:download="buildDocumentName()"
:href="state.href_url"
ref="open_button"
@@ -27,11 +27,15 @@
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,
StoredObjectVersionCreated,
StoredObjectVersionPersisted,
} from "../../types";
interface DownloadButtonConfig {
storedObject: StoredObject;
atVersion: StoredObjectVersion;
atVersion: null | StoredObjectVersionCreated | StoredObjectVersionPersisted;
classes: Record<string, boolean>;
filename?: string;
/**
@@ -70,7 +74,7 @@ function buildDocumentName(): string {
document_name = "document";
}
const ext = mime.getExtension(props.atVersion.type);
const ext = mime.getExtension(props.atVersion?.type ?? "");
if (null !== ext) {
return document_name + "." + ext;

View File

@@ -1,10 +1,24 @@
<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>
</template>
<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 { reactive, useTemplateRef } from "vue";
import { get_versions } from "./HistoryButton/api";
interface HistoryButtonConfig {
@@ -38,29 +52,11 @@ const download_version_and_open_modal = async function (): Promise<void> {
}
};
const onRestoreVersion = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
const onRestoreVersion = (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>
</template>
<style scoped lang="scss">
i.fa::before {
color: var(--bs-dropdown-link-hover-color);

View File

@@ -1,3 +1,22 @@
<template>
<template v-if="props.versions.length > 0">
<div class="container">
<template v-for="v in props.versions" :key="v.id">
<history-button-list-item
:version="v"
:can-edit="canEdit"
:is-current="higher_version === v.version"
:stored-object="storedObject"
@restore-version="onRestored"
></history-button-list-item>
</template>
</div>
</template>
<template v-else>
<p>Chargement des versions</p>
</template>
</template>
<script setup lang="ts">
import {
StoredObject,
@@ -40,33 +59,10 @@ const higher_version = computed<number>(() =>
*
* internally, keep track of the newly restored version
*/
const onRestored = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
const onRestored = (newVersion: StoredObjectVersionWithPointInTime) => {
state.restored = newVersion.version;
emit("restoreVersion", { newVersion });
emit("restoreVersion", newVersion);
};
</script>
<template>
<template v-if="props.versions.length > 0">
<div class="container">
<template v-for="v in props.versions" :key="v.id">
<history-button-list-item
:version="v"
:can-edit="canEdit"
:is-current="higher_version === v.version"
:stored-object="storedObject"
@restore-version="onRestored"
></history-button-list-item>
</template>
</div>
</template>
<template v-else>
<p>Chargement des versions</p>
</template>
</template>
<style scoped lang="scss"></style>

View File

@@ -1,3 +1,70 @@
<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
? 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>&nbsp;#{{ version.version + 1 }}&nbsp;</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" />
</span>
<strong>à</strong>
{{ $d(ISOToDatetime(version.createdAt.datetime8601) ?? 0, "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) ?? 0, "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>
<script setup lang="ts">
import {
StoredObject,
@@ -24,12 +91,8 @@ const emit = defineEmits<{
const props = defineProps<HistoryButtonListItemConfig>();
const onRestore = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
emit("restoreVersion", { newVersion });
const onRestore = (newVersion: StoredObjectVersionWithPointInTime) => {
emit("restoreVersion", newVersion);
};
const isKeptBeforeConversion = computed<boolean>(() => {
@@ -60,77 +123,11 @@ const classes = computed<{
}>(() => ({
row: true,
"row-hover": true,
"blinking-1": props.isRestored && 0 === props.version.version % 2,
"blinking-2": props.isRestored && 1 === props.version.version % 2,
"blinking-1": isRestored.value && 0 === props.version.version % 2,
"blinking-2": isRestored.value && 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>
<div class="col-12">
<file-icon :type="version.type"></file-icon>
<span
><strong>&nbsp;#{{ version.version + 1 }}&nbsp;</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">
div.tags {
span.badge:not(:last-child) {

View File

@@ -1,3 +1,22 @@
<template>
<Teleport to="body">
<modal v-if="state.opened" @close="state.opened = false">
<template v-slot:header>
<h3>Historique des versions du document</h3>
</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="onRestoreVersion"
></history-button-list>
</template>
</modal>
</Teleport>
</template>
<script setup lang="ts">
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import { reactive } from "vue";
@@ -28,29 +47,10 @@ const open = () => {
state.opened = true;
};
const onRestoreVersion = (payload: {
newVersion: StoredObjectVersionWithPointInTime;
}) => emit("restoreVersion", payload);
const onRestoreVersion = (newVersion: StoredObjectVersionWithPointInTime) =>
emit("restoreVersion", newVersion);
defineExpose({ open });
</script>
<template>
<Teleport to="body">
<modal v-if="state.opened" @close="state.opened = false">
<template v-slot:header>
<h3>Historique des versions du document</h3>
</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="onRestoreVersion"
></history-button-list>
</template>
</modal>
</Teleport>
</template>
<style scoped lang="scss"></style>

View File

@@ -1,3 +1,13 @@
<template>
<button
class="btn btn-outline-action"
@click="restore_version_fn"
title="Restaurer"
>
<i class="fa fa-rotate-left"></i> Restaurer
</button>
</template>
<script setup lang="ts">
import {
StoredObjectVersionPersisted,
@@ -22,18 +32,8 @@ 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>
</template>
<style scoped lang="scss"></style>

View File

@@ -1,3 +1,38 @@
<template>
<WaitingScreen :state="state">
<template v-slot:pending>
<p>
{{ trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING) }}
</p>
</template>
<template v-slot:stopped>
<p>
{{ trans(EXPORT_GENERATION_TOO_MANY_RETRIES) }}
</p>
</template>
<template v-slot:failure>
<p>
{{ trans(EXPORT_GENERATION_ERROR_WHILE_GENERATING_EXPORT) }}
</p>
</template>
<template v-slot:ready>
<p>
{{ trans(EXPORT_GENERATION_EXPORT_READY) }}
</p>
<p v-if="storedObject !== null">
<document-action-buttons-group
:stored-object="storedObject"
:filename="filename"
></document-action-buttons-group>
</p>
</template>
</WaitingScreen>
</template>
<script setup lang="ts">
import {
trans,
@@ -87,38 +122,3 @@ onMounted(() => {
onObjectNewStatusCallback();
});
</script>
<template>
<WaitingScreen :state="state">
<template v-slot:pending>
<p>
{{ trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING) }}
</p>
</template>
<template v-slot:stopped>
<p>
{{ trans(EXPORT_GENERATION_TOO_MANY_RETRIES) }}
</p>
</template>
<template v-slot:failure>
<p>
{{ trans(EXPORT_GENERATION_ERROR_WHILE_GENERATING_EXPORT) }}
</p>
</template>
<template v-slot:ready>
<p>
{{ trans(EXPORT_GENERATION_EXPORT_READY) }}
</p>
<p v-if="storedObject !== null">
<document-action-buttons-group
:stored-object="storedObject"
:filename="filename"
></document-action-buttons-group>
</p>
</template>
</WaitingScreen>
</template>

View File

@@ -115,7 +115,7 @@
</teleport>
</template>
<script setup lang="ts">
import { ref, computed, defineEmits, defineProps, useTemplateRef } from "vue";
import { ref, computed, useTemplateRef } from "vue";
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import OnTheFlyCreate from "./Create.vue";
import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue";
@@ -144,6 +144,7 @@ import {
} from "translator";
import PersonEdit from "ChillPersonAssets/vuejs/_components/OnTheFly/PersonEdit.vue";
import ThirdPartyEdit from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdPartyEdit.vue";
import { Person } from "ChillPersonAssets/types";
// Types
type EntityType = "person" | "thirdparty";
@@ -181,7 +182,7 @@ const emit =
defineEmits<
(
e: "saveFormOnTheFly",
payload: { type: string | undefined; data: any },
payload: { type: string | undefined; data: Person },
) => void
>();
@@ -331,12 +332,12 @@ function buildLocation(
async function saveAction() {
if (props.type === "person") {
const person = await castEditPerson.value?.postPerson();
if (null !== person) {
if (person) {
emit("saveFormOnTheFly", { type: props.type, data: person });
}
} else if (props.type === "thirdparty") {
const thirdParty = await castEditThirdParty.value?.postThirdParty();
if (null !== thirdParty) {
if (thirdParty) {
emit("saveFormOnTheFly", { type: props.type, data: thirdParty });
}
}

View File

@@ -76,14 +76,7 @@
</template>
<script lang="ts" setup>
import {
ref,
computed,
defineProps,
defineEmits,
defineComponent,
withDefaults,
} from "vue";
import { ref, computed, defineComponent } from "vue";
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
import {
Entities,
@@ -102,7 +95,6 @@ import {
USER_CURRENT_USER,
trans,
} from "translator";
import { addNewEntities } from "ChillMainAssets/types";
defineComponent({
components: {

View File

@@ -23,9 +23,7 @@ interface SavedExportButtonGenerateConfig {
}
const props = defineProps<SavedExportButtonGenerateConfig>();
const emits = defineEmits<{
(e: "generate");
}>();
const emits = defineEmits<(e: "generate") => void>();
const toast = useToast();
const exportGeneration = ref<ExportGeneration | null>(null);
@@ -157,7 +155,7 @@ const onClickGenerate = async (): Promise<void> => {
<span>{{ trans(EXPORT_GENERATION_TOO_MANY_RETRIES) }}</span>
</div>
<download-button
v-else-if="isReady && storedObject?.currentVersion !== null"
v-else-if="isReady && storedObject && storedObject?.currentVersion !== null"
:classes="buttonClasses"
:stored-object="storedObject"
:at-version="storedObject?.currentVersion"

View File

@@ -17,7 +17,8 @@
:address="data.working_address"
@update-address="onUpdateAddress"
ref="address_modal"
></AddressModal>
v-else-if="data.working_address"
/>
</template>
<script lang="ts" setup>

View File

@@ -20,8 +20,8 @@
<template
v-if="
props.address.addressReference.street !== props.address.street ||
props.address.addressReference.streetNumber !==
props.address.addressReference?.street !== props.address.street ||
props.address.addressReference?.streetNumber !==
props.address.streetNumber
"
>
@@ -31,8 +31,8 @@
>{{ props.address.street }} {{ props.address.streetNumber }}</span
>
<span class="new"
>{{ props.address.addressReference.street }}
{{ props.address.addressReference.streetNumber }}</span
>{{ props.address.addressReference?.street }}
{{ props.address.addressReference?.streetNumber }}</span
>
</div>
</template>
@@ -42,8 +42,8 @@
>{{ props.address.streetNumber }} {{ props.address.street }}</span
>
<span class="new"
>{{ props.address.addressReference.streetNumber }}
{{ props.address.addressReference.street }}</span
>{{ props.address.addressReference?.streetNumber }}
{{ props.address.addressReference?.street }}</span
>
</div>
</template>
@@ -51,7 +51,7 @@
<template
v-if="
props.address.addressReference.postcode.id !==
props.address.addressReference?.postcode.id !==
props.address.postcode.id
"
>
@@ -61,8 +61,8 @@
{{ props.address.postcode.name }}</span
>
<span class="new"
>{{ props.address.addressReference.postcode.code }}
{{ props.address.addressReference.postcode.name }}</span
>{{ props.address.addressReference?.postcode.code }}
{{ props.address.addressReference?.postcode.name }}</span
>
</div>
</template>
@@ -71,9 +71,9 @@
v-if="
props.address.point !== null &&
(props.address.point.coordinates[0] !==
props.address.addressReference.point.coordinates[0] ||
props.address.addressReference?.point.coordinates[0] ||
props.address.point.coordinates[1] !==
props.address.addressReference.point.coordinates[1])
props.address.addressReference?.point.coordinates[1])
"
>
<div class="difference">
@@ -82,8 +82,8 @@
{{ props.address.point.coordinates[1] }}</span
>
<span class="new"
>{{ props.address.addressReference.point.coordinates[0] }}
{{ props.address.addressReference.point.coordinates[1] }}</span
>{{ props.address.addressReference?.point.coordinates[0] }}
{{ props.address.addressReference?.point.coordinates[1] }}</span
>
</div>
</template>

View File

@@ -1,68 +1,3 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from "vue";
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import { ClassicEditor } from "ckeditor5";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import {
trans,
EDITOR_SWITCH_TO_SIMPLE,
EDITOR_SWITCH_TO_COMPLEX,
} from "translator";
const EDITOR_MODE_KEY = "editorMode";
const kind = ref<"simple" | "rich">("simple");
const value = defineModel({ required: true });
const isSimple = computed(() => kind.value === "simple");
const toggleButtonClass = computed(() => {
return {
["toggle-button"]: true,
onEditor: !isSimple.value,
onSimple: isSimple.value,
};
});
const toggleEditor = () => {
let newValue;
newValue = kind.value === "simple" ? "rich" : "simple";
kind.value = "rich";
window.localStorage.setItem(EDITOR_MODE_KEY, newValue);
window.dispatchEvent(new Event("toggleEditorKind"));
};
const onKindChange = function (/* event: StorageEvent | Event */) {
const newValue = window.localStorage.getItem(EDITOR_MODE_KEY);
if (null === newValue || !(newValue === "rich" || newValue === "simple")) {
throw "invalid new value: " + newValue;
}
if (kind.value !== newValue) {
kind.value = newValue;
}
};
onMounted(function () {
const storage = window.localStorage;
const savedKind = storage.getItem(EDITOR_MODE_KEY);
if (null !== kind.value && (savedKind === "simple" || savedKind === "rich")) {
kind.value = savedKind;
}
window.addEventListener("storage", onKindChange);
window.addEventListener("toggleEditorKind", onKindChange);
});
onUnmounted(function () {
window.removeEventListener("storage", onKindChange);
window.removeEventListener("toggleEditorKind", onKindChange);
});
</script>
<template>
<div>
<div v-if="'rich' === kind">
@@ -86,6 +21,80 @@ onUnmounted(function () {
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from "vue";
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
import { ClassicEditor } from "ckeditor5";
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
import {
trans,
EDITOR_SWITCH_TO_SIMPLE,
EDITOR_SWITCH_TO_COMPLEX,
} from "translator";
enum EditorKind {
SIMPLE = "simple",
RICH = "rich",
}
const EDITOR_MODE_KEY = "editorMode";
const kind = ref<EditorKind>(EditorKind.SIMPLE);
const value = defineModel({ required: true, type: String });
const isSimple = computed(() => kind.value === EditorKind.SIMPLE);
const toggleButtonClass = computed(() => {
return {
["toggle-button"]: true,
onEditor: !isSimple.value,
onSimple: isSimple.value,
};
});
const toggleEditor = () => {
const newValue =
kind.value === EditorKind.SIMPLE ? EditorKind.RICH : EditorKind.SIMPLE;
kind.value = newValue;
window.localStorage.setItem(EDITOR_MODE_KEY, newValue);
window.dispatchEvent(new Event("toggleEditorKind"));
};
const onKindChange = function (/* event: StorageEvent | Event */) {
const newValue = window.localStorage.getItem(EDITOR_MODE_KEY);
if (
null === newValue ||
!(newValue === EditorKind.RICH || newValue === EditorKind.SIMPLE)
) {
throw "invalid new value: " + newValue;
}
if (kind.value !== newValue) {
kind.value = newValue;
}
};
onMounted(function () {
const storage = window.localStorage;
const savedKind = storage.getItem(EDITOR_MODE_KEY);
if (
null !== kind.value &&
(savedKind === EditorKind.SIMPLE || savedKind === EditorKind.RICH)
) {
kind.value = savedKind;
}
window.addEventListener("storage", onKindChange);
window.addEventListener("toggleEditorKind", onKindChange);
});
onUnmounted(function () {
window.removeEventListener("storage", onKindChange);
window.removeEventListener("toggleEditorKind", onKindChange);
});
</script>
<style scoped lang="scss">
@import "ChillMainAssets/module/bootstrap/bootstrap";

View File

@@ -104,19 +104,19 @@ interface PickWorkflowConfig {
const props = withDefaults(defineProps<PickWorkflowConfig>(), {
preventDefaultMoveToGenerate: false,
goToGenerateWorkflowPayload: {},
goToGenerateWorkflowPayload: () => ({}),
allowCreateWorkflow: false,
});
const emit = defineEmits<{
(
e: "goToGenerateWorkflow",
{
event: MouseEvent,
workflowName: string,
isLinkValid: boolean,
link: string,
payload: object,
payload: {
event: MouseEvent;
workflowName: string;
isLinkValid: boolean;
link: string;
payload: object;
},
): void;
(e: "clickOpenList"): void;
@@ -159,11 +159,6 @@ const goToGenerateWorkflow = (
payload: props.goToGenerateWorkflowPayload,
});
};
const goToDuplicateRelatedEntity = (
event: MouseEvent,
workflowName: string,
): void => {};
</script>
<style scoped></style>

View File

@@ -1,6 +1,6 @@
<template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-mask" v-if="props.show">
<!-- :: styles bootstrap :: -->
<div
class="modal fade show"
@@ -47,13 +47,14 @@
* [+] modal design can be configured using css classes (size, scroll)
*/
import { trans, MODAL_ACTION_CLOSE } from "translator";
import { defineProps } from "vue";
import type { VNode } from "vue";
defineSlots<{
header?: () => any;
body?: () => any;
footer?: () => any;
"body-head"?: () => any;
header?: () => VNode;
body?: () => VNode;
footer?: () => VNode;
"body-head"?: () => VNode;
}>();
export interface ModalProps {

View File

@@ -308,7 +308,7 @@ export interface AccompanyingPeriodWorkEvaluation {
documents: AccompanyingPeriodWorkEvaluationDocument[];
endDate: DateTime | null;
evaluation: Evaluation | null;
id: number | null;
id: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
key: any;
maxDate: DateTime | null;
@@ -445,31 +445,31 @@ export type EntitiesOrMe = "me" | Entities;
export function isSuggestionForUserGroup(
s: Suggestion,
): s is Suggestion & { result: UserGroup } {
return (s as any)?.result?.type === "user_group";
return (s as Suggestion)?.result?.type === "user_group";
}
export function isSuggestionForUser(
s: Suggestion,
): s is Suggestion & { result: User } {
return (s as any)?.result?.type === "user";
return (s as Suggestion)?.result?.type === "user";
}
export function isSuggestionForPerson(
s: Suggestion,
): s is Suggestion & { result: Person } {
return (s as any)?.result?.type === "person";
return (s as Suggestion)?.result?.type === "person";
}
export function isSuggestionForThirdParty(
s: Suggestion,
): s is Suggestion & { result: Thirdparty } {
return (s as any)?.result?.type === "thirdparty";
return (s as Suggestion)?.result?.type === "thirdparty";
}
export function isSuggestionForHousehold(
s: Suggestion,
): s is Suggestion & { result: Household } {
return (s as any)?.result?.type === "household";
return (s as Suggestion)?.result?.type === "household";
}
export type AddPersonResult = Entities & {

View File

@@ -18,7 +18,7 @@
{{ trans(ACCOMPANYING_COURSE_WORK_START_DATE) }}
:
</span>
<b>{{ formatDate(eval.startDate) }}</b>
<b v-if="eval.startDate">{{ formatDate(eval.startDate) }}</b>
</li>
<li v-if="eval.endDate">
@@ -26,7 +26,7 @@
{{ trans(ACCOMPANYING_COURSE_WORK_END_DATE) }}
:
</span>
<b>{{ formatDate(eval.endDate) }}</b>
<b v-if="eval.endDate">{{ formatDate(eval.endDate) }}</b>
</li>
</ul>
</span>

View File

@@ -23,7 +23,7 @@
<script setup lang="ts">
import { AccompanyingPeriodWorkEvaluation } from "../../../types";
import { defineProps, ref, watch } from "vue";
import { ref, watch } from "vue";
import AccompanyingPeriodWorkEvaluationItem from "ChillPersonAssets/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkEvaluationItem.vue";
// eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@@ -12,7 +12,7 @@
</span>
<ul class="small_in_title columns mt-1">
<li>
<li v-if="acpw.startDate">
<span class="item-key">
{{ trans(ACCOMPANYING_COURSE_WORK_START_DATE) }}
:
@@ -47,9 +47,11 @@ import { AccompanyingPeriodWork } from "../../../types";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const props = defineProps<{ acpw: AccompanyingPeriodWork }>();
const formatDate = (dateObject: DateTime) => {
const formatDate = (dateObject: DateTime | string) => {
if (dateObject) {
const parsedDate = ISOToDate(dateObject.datetime);
let isoString =
typeof dateObject === "string" ? dateObject : dateObject.datetime;
const parsedDate = ISOToDate(isoString);
if (parsedDate) {
return new Intl.DateTimeFormat("default", {
dateStyle: "short",

View File

@@ -24,7 +24,7 @@
<script setup lang="ts">
import AccompanyingPeriodWorkItem from "./AccompanyingPeriodWorkItem.vue";
import { AccompanyingPeriodWork } from "../../../types";
import { defineProps, ref, watch } from "vue";
import { ref, watch } from "vue";
const props = defineProps<{
accompanyingPeriodWorks: AccompanyingPeriodWork[];

View File

@@ -12,7 +12,6 @@
</template>
<script setup lang="ts">
import { defineProps } from "vue";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import HouseholdRenderBox from "ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue";
import { Suggestion } from "ChillPersonAssets/types";

View File

@@ -19,7 +19,7 @@
</template>
<script lang="ts" setup>
import { computed, defineProps } from "vue";
import { computed } from "vue";
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";

View File

@@ -10,7 +10,6 @@
</template>
<script lang="ts" setup>
import { computed, defineProps } from "vue";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
import { Suggestion } from "ChillPersonAssets/types";

View File

@@ -35,9 +35,11 @@
/>
<span v-if="person.birthdate">
{{
// TODO: refactor ISOToDate to alway return Date and dont allow null value as argaument. Manage error with try/catch if needed.
trans(RENDERBOX_BIRTHDAY_STATEMENT, {
gender: toGenderTranslation(person.gender),
birthdate: ISOToDate(person.birthdate?.datetime),
birthdate:
ISOToDate(person.birthdate.datetime) ?? new Date(),
})
}}
</span>
@@ -51,7 +53,8 @@
{{
trans(RENDERBOX_DEATHDATE_STATEMENT, {
gender: toGenderTranslation(person.gender),
deathdate: ISOToDate(person.deathdate?.datetime),
deathdate:
ISOToDate(person.deathdate?.datetime) ?? new Date(),
})
}}
</span>

View File

@@ -8,7 +8,7 @@
<span
class="age"
v-if="addAge && person.birthdate !== null && person.deathdate === null"
>&nbsp;{{ trans(RENDERBOX_YEARS_OLD, person.age) }}</span
>&nbsp;{{ trans(RENDERBOX_YEARS_OLD, { n: person.age }) }}</span
>
<span v-else-if="addAge && person.deathdate !== null">&nbsp;()</span>
</span>
@@ -17,7 +17,7 @@
<script lang="ts" setup>
import { computed, toRefs } from "vue";
import { trans, RENDERBOX_YEARS_OLD } from "translator";
import { AltName, Person } from "ChillPersonAssets/types";
import { Person } from "ChillPersonAssets/types";
const props = defineProps<{
person: Person;

View File

@@ -18,6 +18,7 @@
<div
v-for="err in violations.violationTitles('lastName')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -53,6 +54,7 @@
<div
v-for="err in violations.violationTitles('firstName')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -71,7 +73,7 @@
</div>
<template v-if="action === 'create'">
<div v-for="(a, i) in config.altNames" :key="a.key" class="mb-3">
<div v-for="a in config.altNames" :key="a.key" class="mb-3">
<div class="input-group has-validation">
<div class="form-floating">
<input
@@ -123,6 +125,7 @@
'definition_id',
worker.definition_id.toString(),
)"
:key="err"
class="invalid-feedback was-validated-force"
>
{{ err }}
@@ -154,6 +157,7 @@
<div
v-for="err in violations.violationTitles('gender')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -183,6 +187,7 @@
<div
v-for="err in violations.violationTitles('center')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -212,6 +217,7 @@
<div
v-for="err in violations.violationTitles('civility')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -238,6 +244,7 @@
<div
v-for="err in violations.violationTitles('birthdate')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -265,6 +272,7 @@
<div
v-for="err in violations.violationTitles('phonenumber')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -292,6 +300,7 @@
<div
v-for="err in violations.violationTitles('mobilenumber')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -317,6 +326,7 @@
<div
v-for="err in violations.violationTitles('email')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -353,6 +363,7 @@
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from "vue";
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
import {
@@ -463,7 +474,7 @@ const addAddress = reactive({
target: {},
edit: false,
addressId: null as number | null,
defaults: (window as any).addaddress,
defaults: window.addaddress,
},
});

View File

@@ -1,6 +1,5 @@
import {
Address,
Center,
Civility,
DateTime,
SetAddress,
@@ -8,6 +7,12 @@ import {
User,
} from "ChillMainAssets/types";
declare global {
interface Window {
addaddress: Record<string, unknown>;
}
}
export type ThirdPartyKind = "contact" | "child" | "company";
export interface BaseThirdParty {
@@ -34,7 +39,7 @@ function isBaseThirdParty(t: unknown): t is BaseThirdParty {
if (typeof t !== "object" || t === null) return false;
const o = t as Partial<BaseThirdParty>;
return (
(o as any).type === "thirdparty" &&
o.type === "thirdparty" &&
typeof o.id === "number" &&
typeof o.text === "string" &&
(o.kind === "" ||

View File

@@ -20,13 +20,7 @@
action === 'edit' || action === 'create' || action === 'addContact'
"
>
<ThirdPartyEdit
:id="id"
:type="type"
:action="action"
:query="query"
:parent="parent"
/>
<ThirdPartyEdit :id="id" :type="type" :action="action" :parent="parent" />
</div>
</template>

View File

@@ -41,7 +41,7 @@
</label>
</div>
</div>
<div v-else-if="resolvedParent">
<div v-if="resolvedParent">
<p>Contact de&nbsp;:</p>
<third-party-render-box
:thirdparty="resolvedParent"
@@ -152,6 +152,7 @@
<div
v-for="err in violations.violationTitles('name')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -191,6 +192,7 @@
<div
v-for="err in violations.violationTitles('name')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -238,6 +240,7 @@
<div
v-for="err in violations.violationTitles('email')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -266,6 +269,7 @@
<div
v-for="err in violations.violationTitles('telephone')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -294,6 +298,7 @@
<div
v-for="err in violations.violationTitles('telephone2')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
@@ -315,7 +320,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, getCurrentInstance } from "vue";
import { ref, reactive, computed, onMounted } from "vue";
import ThirdPartyRenderBox from "../Entity/ThirdPartyRenderBox.vue";
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
import {
@@ -339,22 +344,16 @@ import {
THIRDPARTY_MESSAGES_THIRDPARTY_PROFESSION,
THIRDPARTY_MESSAGES_THIRDPARTY_CIVILITY,
THIRDPARTY_MESSAGES_CHILD_OF,
PERSON_EDIT_ERROR_WHILE_SAVING,
} from "translator";
import {
createPerson,
getCivilities,
WritePersonViolationMap,
} from "ChillPersonAssets/vuejs/_api/OnTheFly";
import { getCivilities } from "ChillPersonAssets/vuejs/_api/OnTheFly";
import {
isThirdpartyChild,
isThirdpartyCompany,
Thirdparty,
ThirdpartyCompany,
ThirdPartyKind,
ThirdPartyWrite,
} from "../../../types";
import { Civility, SetCivility } from "ChillMainAssets/types";
import { Civility, TranslatableString } from "ChillMainAssets/types";
import { isValidationException } from "ChillMainAssets/lib/api/apiMethods";
import { useViolationList } from "ChillMainAssets/vuejs/_composables/violationList";
import { useToast } from "vue-toast-notification";
@@ -371,7 +370,7 @@ interface ThirdPartyAddContactProps {
id?: null;
type?: "thirdparty";
action: "addContact";
query?: "";
query?: string;
parent: ThirdpartyCompany;
}
@@ -433,7 +432,6 @@ const addAddress = reactive({
title: { create: "add_an_address_title", edit: "edit_address" },
},
});
const addAddressRef = ref<any>(null);
/**
* We need a specific computed for the kind
@@ -448,11 +446,11 @@ const kind = computed<ThirdPartyKind>({
});
const context = computed(() => {
const ctx: any = {
const ctx: Record<string, unknown> = {
target: { name: props.type, id: props.id },
edit: false,
addressId: null as number | null,
defaults: (window as any).addaddress,
defaults: window.addaddress,
};
if (thirdParty.value.address) {
ctx.addressId = thirdParty.value.address.id;
@@ -496,7 +494,7 @@ const queryItems = computed(() => {
.filter((word) => !lastNameWords.includes(word.toLowerCase()));
});
function localizeString(str: any) {
function localizeString(str: TranslatableString): string {
return _localizeString(str);
}

View File

@@ -21,7 +21,7 @@
</template>
<script lang="ts" setup>
import { ref, watch, defineProps, defineEmits } from "vue";
import { ref, watch } from "vue";
// Components
import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";

View File

@@ -1,6 +1,6 @@
<template>
<div class="row">
<div class="col-12">
<div class="col-12" v-if="content">
<comment-editor v-model="content" />
</div>
<div class="col-12" v-if="motive">

View File

@@ -21,7 +21,7 @@
</template>
<script setup lang="ts">
import { ref, watch, defineProps, defineEmits, computed } from "vue";
import { ref, watch, computed } from "vue";
// Components
import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";

View File

@@ -26,7 +26,7 @@
name:
currentPersons.length > 0
? currentPersons.map((person: Person) => person.text).join(", ")
: undefined,
: "",
})
}}
</h3>

View File

@@ -142,7 +142,7 @@ final readonly class ImportMotivesFromDirectory
// Support parent > child notation in the current language label
$parentName = null;
$childName = trim($labelForSearch);
if (false !== strpos($childName, '>')) {
if (str_contains($childName, '>')) {
[$parentName, $childName] = array_map('trim', explode('>', $childName, 2));
}