mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-02-23 16:50:01 +00:00
Compare commits
2 Commits
2101-fix-v
...
ticket-app
| Author | SHA1 | Date | |
|---|---|---|---|
| 590f4121d0 | |||
|
|
1be2806f37 |
@@ -97,12 +97,10 @@ 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/
|
||||
@@ -110,15 +108,12 @@ 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/
|
||||
@@ -136,8 +131,6 @@ phpstan_tests:
|
||||
- bin/console cache:clear --env=dev
|
||||
script:
|
||||
- composer exec phpstan -- analyze --memory-limit=3G
|
||||
dependencies:
|
||||
- build
|
||||
cache:
|
||||
paths:
|
||||
- .cache/
|
||||
@@ -153,8 +146,6 @@ rector_tests:
|
||||
- bin/console cache:clear --env=dev
|
||||
script:
|
||||
- composer exec rector -- process --dry-run
|
||||
dependencies:
|
||||
- build
|
||||
cache:
|
||||
paths:
|
||||
- .cache/
|
||||
@@ -173,37 +164,16 @@ 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
|
||||
@@ -229,8 +199,6 @@ 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:
|
||||
|
||||
@@ -71,11 +71,4 @@ export function isEventInputCalendarRange(
|
||||
return typeof toBeDetermined.is === "string" && toBeDetermined.is === "range";
|
||||
}
|
||||
|
||||
export enum AnswerStatus {
|
||||
ACCEPTED = "accepted",
|
||||
DECLINED = "declined",
|
||||
PENDING = "pending",
|
||||
TENTATIVE = "tentative",
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
@@ -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,6 +42,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "CalendarActive",
|
||||
props: {
|
||||
|
||||
@@ -24,14 +24,6 @@ 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",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -47,38 +47,77 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { AnswerStatus } from "../../types";
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
calendarId: number;
|
||||
status: AnswerStatus;
|
||||
}>();
|
||||
const ACCEPTED = "accepted";
|
||||
const DECLINED = "declined";
|
||||
const PENDING = "pending";
|
||||
const TENTATIVELY_ACCEPTED = "tentative";
|
||||
|
||||
const emit =
|
||||
defineEmits<(e: "statusChanged", newStatus: AnswerStatus) => void>();
|
||||
|
||||
const Statuses = {
|
||||
ACCEPTED: AnswerStatus.ACCEPTED,
|
||||
DECLINED: AnswerStatus.DECLINED,
|
||||
PENDING: AnswerStatus.PENDING,
|
||||
TENTATIVELY_ACCEPTED: AnswerStatus.TENTATIVE,
|
||||
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",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
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);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -146,11 +146,7 @@
|
||||
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>
|
||||
@@ -160,11 +156,7 @@
|
||||
</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>
|
||||
|
||||
@@ -74,12 +74,12 @@ const saveAndClose = function (e: Event): void {
|
||||
location: location.value,
|
||||
calendarRangeId: calendarRangeId.value,
|
||||
})
|
||||
.then(() => {
|
||||
.then((_) => {
|
||||
showModal.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const closeModal = function (): void {
|
||||
const closeModal = function (_: any): void {
|
||||
showModal.value = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@ 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 () {
|
||||
window.addEventListener("DOMContentLoaded", function (e) {
|
||||
document
|
||||
.querySelectorAll<HTMLDivElement>("div[data-download-buttons]")
|
||||
.forEach((el) => {
|
||||
|
||||
@@ -9,7 +9,6 @@ export interface StoredObject {
|
||||
uuid: string;
|
||||
prefix: string;
|
||||
status: StoredObjectStatus;
|
||||
type: string;
|
||||
currentVersion:
|
||||
| null
|
||||
| StoredObjectVersionCreated
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<li v-if="isEditableOnDesktop">
|
||||
<desktop-edit-button
|
||||
:classes="{ 'dropdown-item': true }"
|
||||
:edit-link="props.davLink ?? ''"
|
||||
:expiration-link="props.davLinkExpiration ?? 0"
|
||||
:edit-link="props.davLink"
|
||||
:expiration-link="props.davLinkExpiration"
|
||||
></desktop-edit-button>
|
||||
</li>
|
||||
<li v-if="isConvertibleToPdf">
|
||||
@@ -75,6 +75,7 @@ import {
|
||||
import {
|
||||
StoredObject,
|
||||
StoredObjectStatusChange,
|
||||
StoredObjectVersion,
|
||||
WopiEditButtonExecutableBeforeLeaveFunction,
|
||||
} from "../types";
|
||||
import DesktopEditButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DesktopEditButton.vue";
|
||||
@@ -205,6 +206,10 @@ 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);
|
||||
|
||||
@@ -1,35 +1,3 @@
|
||||
<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 {
|
||||
@@ -41,23 +9,24 @@ import { computed, ref, Ref } from "vue";
|
||||
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
|
||||
|
||||
interface DropFileConfig {
|
||||
existingDoc: StoredObject | null;
|
||||
existingDoc?: StoredObject;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<DropFileConfig>(), {
|
||||
existingDoc: null,
|
||||
});
|
||||
|
||||
const emit = defineEmits<
|
||||
(
|
||||
e: "addDocument",
|
||||
payload: {
|
||||
stored_object_version: StoredObjectVersionCreated;
|
||||
stored_object: StoredObject;
|
||||
file_name: string;
|
||||
},
|
||||
) => void
|
||||
>();
|
||||
const emit =
|
||||
defineEmits<
|
||||
(
|
||||
e: "addDocument",
|
||||
{
|
||||
stored_object_version: StoredObjectVersionCreated,
|
||||
stored_object: StoredObject,
|
||||
file_name: string,
|
||||
},
|
||||
) => void
|
||||
>();
|
||||
|
||||
const is_dragging: Ref<boolean> = ref(false);
|
||||
const uploading: Ref<boolean> = ref(false);
|
||||
@@ -165,6 +134,38 @@ 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%;
|
||||
|
||||
@@ -18,10 +18,10 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
|
||||
const emit = defineEmits<{
|
||||
(
|
||||
e: "addDocument",
|
||||
payload: {
|
||||
stored_object: StoredObject;
|
||||
stored_object_version: StoredObjectVersion;
|
||||
file_name: string;
|
||||
{
|
||||
stored_object: StoredObject,
|
||||
stored_object_version: StoredObjectVersion,
|
||||
file_name: string,
|
||||
},
|
||||
): void;
|
||||
(e: "removeDocument"): void;
|
||||
|
||||
@@ -1,34 +1,6 @@
|
||||
<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 } from "vue";
|
||||
import { computed, ref, Ref } from "vue";
|
||||
import DropFile from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFile.vue";
|
||||
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
|
||||
|
||||
@@ -44,15 +16,19 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
|
||||
const emit = defineEmits<{
|
||||
(
|
||||
e: "addDocument",
|
||||
payload: {
|
||||
stored_object: StoredObject;
|
||||
stored_object_version: StoredObjectVersion;
|
||||
file_name: string;
|
||||
{
|
||||
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;
|
||||
@@ -93,4 +69,33 @@ 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>
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
<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
|
||||
@@ -35,12 +43,4 @@
|
||||
<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>
|
||||
|
||||
@@ -1,3 +1,42 @@
|
||||
<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">
|
||||
@@ -51,41 +90,3 @@ 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>
|
||||
|
||||
@@ -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,15 +27,11 @@
|
||||
import { reactive, ref, nextTick, onMounted } from "vue";
|
||||
import { download_and_decrypt_doc } from "./helpers";
|
||||
import mime from "mime";
|
||||
import {
|
||||
StoredObject,
|
||||
StoredObjectVersionCreated,
|
||||
StoredObjectVersionPersisted,
|
||||
} from "../../types";
|
||||
import { StoredObject, StoredObjectVersion } from "../../types";
|
||||
|
||||
interface DownloadButtonConfig {
|
||||
storedObject: StoredObject;
|
||||
atVersion: null | StoredObjectVersionCreated | StoredObjectVersionPersisted;
|
||||
atVersion: StoredObjectVersion;
|
||||
classes: Record<string, boolean>;
|
||||
filename?: string;
|
||||
/**
|
||||
@@ -74,7 +70,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;
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
<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 { reactive, useTemplateRef } from "vue";
|
||||
import { computed, reactive, ref, useTemplateRef } from "vue";
|
||||
import { get_versions } from "./HistoryButton/api";
|
||||
|
||||
interface HistoryButtonConfig {
|
||||
@@ -52,11 +38,29 @@ const download_version_and_open_modal = async function (): Promise<void> {
|
||||
}
|
||||
};
|
||||
|
||||
const onRestoreVersion = (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>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
i.fa::before {
|
||||
color: var(--bs-dropdown-link-hover-color);
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
<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,
|
||||
@@ -59,10 +40,33 @@ const higher_version = computed<number>(() =>
|
||||
*
|
||||
* internally, keep track of the newly restored version
|
||||
*/
|
||||
const onRestored = (newVersion: StoredObjectVersionWithPointInTime) => {
|
||||
const onRestored = ({
|
||||
newVersion,
|
||||
}: {
|
||||
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>
|
||||
|
||||
@@ -1,70 +1,3 @@
|
||||
<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> #{{ 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" />
|
||||
</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,
|
||||
@@ -91,8 +24,12 @@ const emit = defineEmits<{
|
||||
|
||||
const props = defineProps<HistoryButtonListItemConfig>();
|
||||
|
||||
const onRestore = (newVersion: StoredObjectVersionWithPointInTime) => {
|
||||
emit("restoreVersion", newVersion);
|
||||
const onRestore = ({
|
||||
newVersion,
|
||||
}: {
|
||||
newVersion: StoredObjectVersionWithPointInTime;
|
||||
}) => {
|
||||
emit("restoreVersion", { newVersion });
|
||||
};
|
||||
|
||||
const isKeptBeforeConversion = computed<boolean>(() => {
|
||||
@@ -123,11 +60,77 @@ const classes = computed<{
|
||||
}>(() => ({
|
||||
row: true,
|
||||
"row-hover": true,
|
||||
"blinking-1": isRestored.value && 0 === props.version.version % 2,
|
||||
"blinking-2": isRestored.value && 1 === props.version.version % 2,
|
||||
"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>
|
||||
<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">
|
||||
div.tags {
|
||||
span.badge:not(:last-child) {
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
<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";
|
||||
@@ -47,10 +28,29 @@ const open = () => {
|
||||
state.opened = true;
|
||||
};
|
||||
|
||||
const onRestoreVersion = (newVersion: StoredObjectVersionWithPointInTime) =>
|
||||
emit("restoreVersion", newVersion);
|
||||
const onRestoreVersion = (payload: {
|
||||
newVersion: StoredObjectVersionWithPointInTime;
|
||||
}) => emit("restoreVersion", payload);
|
||||
|
||||
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>
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
<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,
|
||||
@@ -32,8 +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>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,38 +1,3 @@
|
||||
<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,
|
||||
@@ -122,3 +87,38 @@ 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>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { computed, ComputedRef, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
@@ -82,6 +82,7 @@ import {
|
||||
CONFIDENTIAL,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
|
||||
const store = useStore();
|
||||
@@ -103,6 +104,12 @@ const noResults = computed(() => {
|
||||
function getUrl(c: { id: number }): string {
|
||||
return `/fr/parcours/${c.id}`;
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyAccompanyingCourses,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
@@ -112,6 +112,7 @@ import {
|
||||
trans,
|
||||
} from "translator";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const evaluations: ComputedRef<
|
||||
PaginationResponse<AccompanyingPeriodWorkEvaluation>
|
||||
@@ -150,6 +151,12 @@ function getUrl(
|
||||
}
|
||||
return "";
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyEvaluations,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { computed, ComputedRef, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import { Notification } from "ChillPersonAssets/types";
|
||||
@@ -66,6 +66,7 @@ import {
|
||||
} from "translator";
|
||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -121,6 +122,12 @@ function getEntityUrl(n: Notification): string {
|
||||
throw "notification type unknown";
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyNotifications,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { computed, ComputedRef, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import {
|
||||
@@ -95,6 +95,7 @@ import {
|
||||
import { TasksState } from "./store/modules/homepage";
|
||||
import { Alert, Warning } from "ChillPersonAssets/types";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -123,6 +124,12 @@ const noResultsWarning = computed(() => {
|
||||
function getUrl(t: Warning | Alert): string {
|
||||
return `/fr/task/single-task/${t.id}/show`;
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyTasks,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import MyWorkflowsTable from "./MyWorkflowsTable.vue";
|
||||
import {
|
||||
@@ -19,9 +19,16 @@ import {
|
||||
MY_WORKFLOWS_DESCRIPTION_CC,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const workflows = computed(() => store.state.homepage.workflows);
|
||||
const workflowsCc = computed(() => store.state.homepage.workflowsCc);
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyWorkflows,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
</teleport>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, useTemplateRef } from "vue";
|
||||
import { ref, computed, defineEmits, defineProps, 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,7 +144,6 @@ 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";
|
||||
@@ -182,7 +181,7 @@ const emit =
|
||||
defineEmits<
|
||||
(
|
||||
e: "saveFormOnTheFly",
|
||||
payload: { type: string | undefined; data: Person },
|
||||
payload: { type: string | undefined; data: any },
|
||||
) => void
|
||||
>();
|
||||
|
||||
@@ -332,12 +331,12 @@ function buildLocation(
|
||||
async function saveAction() {
|
||||
if (props.type === "person") {
|
||||
const person = await castEditPerson.value?.postPerson();
|
||||
if (person) {
|
||||
if (null !== person) {
|
||||
emit("saveFormOnTheFly", { type: props.type, data: person });
|
||||
}
|
||||
} else if (props.type === "thirdparty") {
|
||||
const thirdParty = await castEditThirdParty.value?.postThirdParty();
|
||||
if (thirdParty) {
|
||||
if (null !== thirdParty) {
|
||||
emit("saveFormOnTheFly", { type: props.type, data: thirdParty });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, defineComponent } from "vue";
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineComponent,
|
||||
withDefaults,
|
||||
} from "vue";
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
import {
|
||||
Entities,
|
||||
@@ -95,6 +102,7 @@ import {
|
||||
USER_CURRENT_USER,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { addNewEntities } from "ChillMainAssets/types";
|
||||
|
||||
defineComponent({
|
||||
components: {
|
||||
|
||||
@@ -23,7 +23,9 @@ interface SavedExportButtonGenerateConfig {
|
||||
}
|
||||
|
||||
const props = defineProps<SavedExportButtonGenerateConfig>();
|
||||
const emits = defineEmits<(e: "generate") => void>();
|
||||
const emits = defineEmits<{
|
||||
(e: "generate");
|
||||
}>();
|
||||
|
||||
const toast = useToast();
|
||||
const exportGeneration = ref<ExportGeneration | null>(null);
|
||||
@@ -155,7 +157,7 @@ const onClickGenerate = async (): Promise<void> => {
|
||||
<span>{{ trans(EXPORT_GENERATION_TOO_MANY_RETRIES) }}</span>
|
||||
</div>
|
||||
<download-button
|
||||
v-else-if="isReady && storedObject && storedObject?.currentVersion !== null"
|
||||
v-else-if="isReady && storedObject?.currentVersion !== null"
|
||||
:classes="buttonClasses"
|
||||
:stored-object="storedObject"
|
||||
:at-version="storedObject?.currentVersion"
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
:address="data.working_address"
|
||||
@update-address="onUpdateAddress"
|
||||
ref="address_modal"
|
||||
v-else-if="data.working_address"
|
||||
/>
|
||||
></AddressModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +1,68 @@
|
||||
<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">
|
||||
@@ -21,80 +86,6 @@
|
||||
</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";
|
||||
|
||||
|
||||
@@ -104,19 +104,19 @@ interface PickWorkflowConfig {
|
||||
|
||||
const props = withDefaults(defineProps<PickWorkflowConfig>(), {
|
||||
preventDefaultMoveToGenerate: false,
|
||||
goToGenerateWorkflowPayload: () => ({}),
|
||||
goToGenerateWorkflowPayload: {},
|
||||
allowCreateWorkflow: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(
|
||||
e: "goToGenerateWorkflow",
|
||||
payload: {
|
||||
event: MouseEvent;
|
||||
workflowName: string;
|
||||
isLinkValid: boolean;
|
||||
link: string;
|
||||
payload: object;
|
||||
{
|
||||
event: MouseEvent,
|
||||
workflowName: string,
|
||||
isLinkValid: boolean,
|
||||
link: string,
|
||||
payload: object,
|
||||
},
|
||||
): void;
|
||||
(e: "clickOpenList"): void;
|
||||
@@ -159,6 +159,11 @@ const goToGenerateWorkflow = (
|
||||
payload: props.goToGenerateWorkflowPayload,
|
||||
});
|
||||
};
|
||||
|
||||
const goToDuplicateRelatedEntity = (
|
||||
event: MouseEvent,
|
||||
workflowName: string,
|
||||
): void => {};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<transition name="modal">
|
||||
<div class="modal-mask" v-if="props.show">
|
||||
<div class="modal-mask">
|
||||
<!-- :: styles bootstrap :: -->
|
||||
<div
|
||||
class="modal fade show"
|
||||
@@ -47,14 +47,13 @@
|
||||
* [+] modal design can be configured using css classes (size, scroll)
|
||||
*/
|
||||
import { trans, MODAL_ACTION_CLOSE } from "translator";
|
||||
|
||||
import type { VNode } from "vue";
|
||||
import { defineProps } from "vue";
|
||||
|
||||
defineSlots<{
|
||||
header?: () => VNode;
|
||||
body?: () => VNode;
|
||||
footer?: () => VNode;
|
||||
"body-head"?: () => VNode;
|
||||
header?: () => any;
|
||||
body?: () => any;
|
||||
footer?: () => any;
|
||||
"body-head"?: () => any;
|
||||
}>();
|
||||
|
||||
export interface ModalProps {
|
||||
|
||||
@@ -308,7 +308,7 @@ export interface AccompanyingPeriodWorkEvaluation {
|
||||
documents: AccompanyingPeriodWorkEvaluationDocument[];
|
||||
endDate: DateTime | null;
|
||||
evaluation: Evaluation | null;
|
||||
id: number;
|
||||
id: number | null;
|
||||
// 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 Suggestion)?.result?.type === "user_group";
|
||||
return (s as any)?.result?.type === "user_group";
|
||||
}
|
||||
|
||||
export function isSuggestionForUser(
|
||||
s: Suggestion,
|
||||
): s is Suggestion & { result: User } {
|
||||
return (s as Suggestion)?.result?.type === "user";
|
||||
return (s as any)?.result?.type === "user";
|
||||
}
|
||||
|
||||
export function isSuggestionForPerson(
|
||||
s: Suggestion,
|
||||
): s is Suggestion & { result: Person } {
|
||||
return (s as Suggestion)?.result?.type === "person";
|
||||
return (s as any)?.result?.type === "person";
|
||||
}
|
||||
|
||||
export function isSuggestionForThirdParty(
|
||||
s: Suggestion,
|
||||
): s is Suggestion & { result: Thirdparty } {
|
||||
return (s as Suggestion)?.result?.type === "thirdparty";
|
||||
return (s as any)?.result?.type === "thirdparty";
|
||||
}
|
||||
|
||||
export function isSuggestionForHousehold(
|
||||
s: Suggestion,
|
||||
): s is Suggestion & { result: Household } {
|
||||
return (s as Suggestion)?.result?.type === "household";
|
||||
return (s as any)?.result?.type === "household";
|
||||
}
|
||||
|
||||
export type AddPersonResult = Entities & {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
{{ trans(ACCOMPANYING_COURSE_WORK_START_DATE) }}
|
||||
:
|
||||
</span>
|
||||
<b v-if="eval.startDate">{{ formatDate(eval.startDate) }}</b>
|
||||
<b>{{ formatDate(eval.startDate) }}</b>
|
||||
</li>
|
||||
|
||||
<li v-if="eval.endDate">
|
||||
@@ -26,7 +26,7 @@
|
||||
{{ trans(ACCOMPANYING_COURSE_WORK_END_DATE) }}
|
||||
:
|
||||
</span>
|
||||
<b v-if="eval.endDate">{{ formatDate(eval.endDate) }}</b>
|
||||
<b>{{ formatDate(eval.endDate) }}</b>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AccompanyingPeriodWorkEvaluation } from "../../../types";
|
||||
import { ref, watch } from "vue";
|
||||
import { defineProps, ref, watch } from "vue";
|
||||
import AccompanyingPeriodWorkEvaluationItem from "ChillPersonAssets/vuejs/_components/AccompanyingPeriodWorkSelector/AccompanyingPeriodWorkEvaluationItem.vue";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</span>
|
||||
|
||||
<ul class="small_in_title columns mt-1">
|
||||
<li v-if="acpw.startDate">
|
||||
<li>
|
||||
<span class="item-key">
|
||||
{{ trans(ACCOMPANYING_COURSE_WORK_START_DATE) }}
|
||||
:
|
||||
@@ -47,11 +47,9 @@ import { AccompanyingPeriodWork } from "../../../types";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const props = defineProps<{ acpw: AccompanyingPeriodWork }>();
|
||||
const formatDate = (dateObject: DateTime | string) => {
|
||||
const formatDate = (dateObject: DateTime) => {
|
||||
if (dateObject) {
|
||||
let isoString =
|
||||
typeof dateObject === "string" ? dateObject : dateObject.datetime;
|
||||
const parsedDate = ISOToDate(isoString);
|
||||
const parsedDate = ISOToDate(dateObject.datetime);
|
||||
if (parsedDate) {
|
||||
return new Intl.DateTimeFormat("default", {
|
||||
dateStyle: "short",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<script setup lang="ts">
|
||||
import AccompanyingPeriodWorkItem from "./AccompanyingPeriodWorkItem.vue";
|
||||
import { AccompanyingPeriodWork } from "../../../types";
|
||||
import { ref, watch } from "vue";
|
||||
import { defineProps, ref, watch } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
accompanyingPeriodWorks: AccompanyingPeriodWork[];
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
</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";
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { computed, defineProps } 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";
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
</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";
|
||||
|
||||
@@ -35,11 +35,9 @@
|
||||
/>
|
||||
<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) ?? new Date(),
|
||||
birthdate: ISOToDate(person.birthdate?.datetime),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
@@ -53,8 +51,7 @@
|
||||
{{
|
||||
trans(RENDERBOX_DEATHDATE_STATEMENT, {
|
||||
gender: toGenderTranslation(person.gender),
|
||||
deathdate:
|
||||
ISOToDate(person.deathdate?.datetime) ?? new Date(),
|
||||
deathdate: ISOToDate(person.deathdate?.datetime),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<span
|
||||
class="age"
|
||||
v-if="addAge && person.birthdate !== null && person.deathdate === null"
|
||||
> {{ trans(RENDERBOX_YEARS_OLD, { n: person.age }) }}</span
|
||||
> {{ trans(RENDERBOX_YEARS_OLD, person.age) }}</span
|
||||
>
|
||||
<span v-else-if="addAge && person.deathdate !== null"> (‡)</span>
|
||||
</span>
|
||||
@@ -17,7 +17,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, toRefs } from "vue";
|
||||
import { trans, RENDERBOX_YEARS_OLD } from "translator";
|
||||
import { Person } from "ChillPersonAssets/types";
|
||||
import { AltName, Person } from "ChillPersonAssets/types";
|
||||
|
||||
const props = defineProps<{
|
||||
person: Person;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('lastName')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -54,7 +53,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('firstName')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -73,7 +71,7 @@
|
||||
</div>
|
||||
|
||||
<template v-if="action === 'create'">
|
||||
<div v-for="a in config.altNames" :key="a.key" class="mb-3">
|
||||
<div v-for="(a, i) in config.altNames" :key="a.key" class="mb-3">
|
||||
<div class="input-group has-validation">
|
||||
<div class="form-floating">
|
||||
<input
|
||||
@@ -125,7 +123,6 @@
|
||||
'definition_id',
|
||||
worker.definition_id.toString(),
|
||||
)"
|
||||
:key="err"
|
||||
class="invalid-feedback was-validated-force"
|
||||
>
|
||||
{{ err }}
|
||||
@@ -157,7 +154,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('gender')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -187,7 +183,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('center')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -217,7 +212,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('civility')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -244,7 +238,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('birthdate')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -272,7 +265,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('phonenumber')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -300,7 +292,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('mobilenumber')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -326,7 +317,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('email')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -363,7 +353,6 @@
|
||||
|
||||
<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 {
|
||||
@@ -474,7 +463,7 @@ const addAddress = reactive({
|
||||
target: {},
|
||||
edit: false,
|
||||
addressId: null as number | null,
|
||||
defaults: window.addaddress,
|
||||
defaults: (window as any).addaddress,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
Address,
|
||||
Center,
|
||||
Civility,
|
||||
DateTime,
|
||||
SetAddress,
|
||||
@@ -7,12 +8,6 @@ import {
|
||||
User,
|
||||
} from "ChillMainAssets/types";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
addaddress: Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
|
||||
export type ThirdPartyKind = "contact" | "child" | "company";
|
||||
|
||||
export interface BaseThirdParty {
|
||||
@@ -39,7 +34,7 @@ function isBaseThirdParty(t: unknown): t is BaseThirdParty {
|
||||
if (typeof t !== "object" || t === null) return false;
|
||||
const o = t as Partial<BaseThirdParty>;
|
||||
return (
|
||||
o.type === "thirdparty" &&
|
||||
(o as any).type === "thirdparty" &&
|
||||
typeof o.id === "number" &&
|
||||
typeof o.text === "string" &&
|
||||
(o.kind === "" ||
|
||||
|
||||
@@ -20,7 +20,13 @@
|
||||
action === 'edit' || action === 'create' || action === 'addContact'
|
||||
"
|
||||
>
|
||||
<ThirdPartyEdit :id="id" :type="type" :action="action" :parent="parent" />
|
||||
<ThirdPartyEdit
|
||||
:id="id"
|
||||
:type="type"
|
||||
:action="action"
|
||||
:query="query"
|
||||
:parent="parent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="resolvedParent">
|
||||
<div v-else-if="resolvedParent">
|
||||
<p>Contact de :</p>
|
||||
<third-party-render-box
|
||||
:thirdparty="resolvedParent"
|
||||
@@ -152,7 +152,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('name')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -192,7 +191,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('name')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -240,7 +238,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('email')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -269,7 +266,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('telephone')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -298,7 +294,6 @@
|
||||
<div
|
||||
v-for="err in violations.violationTitles('telephone2')"
|
||||
class="invalid-feedback was-validated-force"
|
||||
:key="err"
|
||||
>
|
||||
{{ err }}
|
||||
</div>
|
||||
@@ -320,7 +315,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from "vue";
|
||||
import { ref, reactive, computed, onMounted, getCurrentInstance } from "vue";
|
||||
import ThirdPartyRenderBox from "../Entity/ThirdPartyRenderBox.vue";
|
||||
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
|
||||
import {
|
||||
@@ -344,16 +339,22 @@ import {
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_PROFESSION,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_CIVILITY,
|
||||
THIRDPARTY_MESSAGES_CHILD_OF,
|
||||
PERSON_EDIT_ERROR_WHILE_SAVING,
|
||||
} from "translator";
|
||||
import { getCivilities } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||
import {
|
||||
createPerson,
|
||||
getCivilities,
|
||||
WritePersonViolationMap,
|
||||
} from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||
import {
|
||||
isThirdpartyChild,
|
||||
isThirdpartyCompany,
|
||||
Thirdparty,
|
||||
ThirdpartyCompany,
|
||||
ThirdPartyKind,
|
||||
ThirdPartyWrite,
|
||||
} from "../../../types";
|
||||
import { Civility, TranslatableString } from "ChillMainAssets/types";
|
||||
import { Civility, SetCivility } from "ChillMainAssets/types";
|
||||
import { isValidationException } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { useViolationList } from "ChillMainAssets/vuejs/_composables/violationList";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
@@ -370,7 +371,7 @@ interface ThirdPartyAddContactProps {
|
||||
id?: null;
|
||||
type?: "thirdparty";
|
||||
action: "addContact";
|
||||
query?: string;
|
||||
query?: "";
|
||||
parent: ThirdpartyCompany;
|
||||
}
|
||||
|
||||
@@ -432,6 +433,7 @@ 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
|
||||
@@ -446,11 +448,11 @@ const kind = computed<ThirdPartyKind>({
|
||||
});
|
||||
|
||||
const context = computed(() => {
|
||||
const ctx: Record<string, unknown> = {
|
||||
const ctx: any = {
|
||||
target: { name: props.type, id: props.id },
|
||||
edit: false,
|
||||
addressId: null as number | null,
|
||||
defaults: window.addaddress,
|
||||
defaults: (window as any).addaddress,
|
||||
};
|
||||
if (thirdParty.value.address) {
|
||||
ctx.addressId = thirdParty.value.address.id;
|
||||
@@ -494,7 +496,7 @@ const queryItems = computed(() => {
|
||||
.filter((word) => !lastNameWords.includes(word.toLowerCase()));
|
||||
});
|
||||
|
||||
function localizeString(str: TranslatableString): string {
|
||||
function localizeString(str: any) {
|
||||
return _localizeString(str);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Center,
|
||||
DateTime,
|
||||
TranslatableString,
|
||||
User,
|
||||
@@ -148,8 +149,9 @@ export type TicketHistoryLine =
|
||||
| CallerStateEvent;
|
||||
|
||||
interface BaseTicket<
|
||||
T extends "ticket_ticket:simple" | "ticket_ticket:extended" =
|
||||
"ticket_ticket:simple",
|
||||
T extends
|
||||
| "ticket_ticket:simple"
|
||||
| "ticket_ticket:extended" = "ticket_ticket:simple",
|
||||
> {
|
||||
type_extended: T;
|
||||
type: "ticket_ticket";
|
||||
@@ -177,6 +179,7 @@ export interface Ticket extends BaseTicket<"ticket_ticket:extended"> {
|
||||
}
|
||||
|
||||
export interface TicketFilters {
|
||||
byPersonCenter: Center[];
|
||||
byPerson: Person[];
|
||||
byCreator: User[];
|
||||
byAddressee: UserGroupOrUser[];
|
||||
@@ -191,6 +194,7 @@ export interface TicketFilters {
|
||||
}
|
||||
|
||||
export interface TicketFilterParams {
|
||||
byPersonCenter?: number[];
|
||||
byPerson?: number[];
|
||||
byCreator?: number[];
|
||||
byAddressee?: number[];
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ref, watch, defineProps, defineEmits } from "vue";
|
||||
|
||||
// Components
|
||||
import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col-12" v-if="content">
|
||||
<div class="col-12">
|
||||
<comment-editor v-model="content" />
|
||||
</div>
|
||||
<div class="col-12" v-if="motive">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
name:
|
||||
currentPersons.length > 0
|
||||
? currentPersons.map((person: Person) => person.text).join(", ")
|
||||
: "",
|
||||
: undefined,
|
||||
})
|
||||
}}
|
||||
</h3>
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
<!-- Sélection du motif -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{{
|
||||
trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE)
|
||||
}}</label>
|
||||
<label class="form-label">
|
||||
{{ trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE) }} *
|
||||
</label>
|
||||
<motive-selector-component
|
||||
v-model="ticketForm.motive"
|
||||
:motives="motives"
|
||||
@@ -49,9 +49,9 @@
|
||||
|
||||
<!-- Éditeur de commentaire -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{{
|
||||
trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE)
|
||||
}}</label>
|
||||
<label class="form-label">
|
||||
{{ trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE) }} *
|
||||
</label>
|
||||
<comment-editor-component
|
||||
v-model="ticketForm.content"
|
||||
:motive="ticketForm.motive ? ticketForm.motive : null"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { makeFetch } from "../../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
||||
import { Person } from "../../../../../../../../ChillPersonBundle/Resources/public/types";
|
||||
import { ApiException } from "../../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import {
|
||||
ApiException,
|
||||
Center,
|
||||
} from "../../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import { Module } from "vuex";
|
||||
import { RootState } from "..";
|
||||
import { Ticket } from ".././../../../types";
|
||||
@@ -8,21 +11,29 @@ import { Thirdparty } from "src/Bundle/ChillThirdPartyBundle/Resources/public/ty
|
||||
|
||||
export interface State {
|
||||
persons: Person[];
|
||||
centers: Center[];
|
||||
}
|
||||
|
||||
export const modulePersons: Module<State, RootState> = {
|
||||
state: () => ({
|
||||
persons: [] as Person[],
|
||||
centers: [] as Center[],
|
||||
}),
|
||||
getters: {
|
||||
getPersons(state) {
|
||||
return state.persons;
|
||||
},
|
||||
getCenters(state) {
|
||||
return state.centers;
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setPersons(state, persons: Person[]) {
|
||||
state.persons = persons;
|
||||
},
|
||||
setCenters(state, centers: Center[]) {
|
||||
state.centers = centers;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async setPersons({ commit, rootState }, persons: Person[]) {
|
||||
@@ -81,5 +92,15 @@ export const modulePersons: Module<State, RootState> = {
|
||||
throw error.name;
|
||||
}
|
||||
},
|
||||
async fetchCenters({ commit }) {
|
||||
try {
|
||||
const result: { showCenters: boolean; centers: Center[] } =
|
||||
await makeFetch("GET", "/api/1.0/person/creation/authorized-centers");
|
||||
commit("setCenters", result.showCenters ? result.centers : []);
|
||||
} catch (e: unknown) {
|
||||
const error = e as ApiException;
|
||||
throw error.name;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface State {
|
||||
ticket_list: TicketSimple[];
|
||||
pagination: Pagination;
|
||||
count: number;
|
||||
latest_update: Date | null;
|
||||
user: User;
|
||||
}
|
||||
|
||||
@@ -28,6 +29,7 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
next: null,
|
||||
previous: null,
|
||||
},
|
||||
latest_update: null,
|
||||
count: 0,
|
||||
user: {} as User,
|
||||
}),
|
||||
@@ -49,6 +51,9 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
getCount(state): number {
|
||||
return state.count;
|
||||
},
|
||||
getLatestUpdate(state): Date | null {
|
||||
return state.latest_update;
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setTicketList(state, ticketList: TicketSimple[]) {
|
||||
@@ -63,6 +68,9 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
setCount(state, count: number) {
|
||||
state.count = count;
|
||||
},
|
||||
setLatestUpdate(state, date: Date) {
|
||||
state.latest_update = date;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async fetchTicketList(
|
||||
@@ -95,6 +103,7 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
|
||||
commit("setTicketList", results);
|
||||
commit("setCount", count);
|
||||
commit("setLatestUpdate", new Date());
|
||||
commit("setPagination", pagination);
|
||||
} catch (e: unknown) {
|
||||
const error = e as ApiException;
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<ticket-filter-list-component
|
||||
:resultCount="resultCount"
|
||||
:available-centers="availableCenters"
|
||||
:latest-update="latestUpdate"
|
||||
:result-count="resultCount"
|
||||
:available-persons="availablePersons"
|
||||
:available-motives="availableMotives"
|
||||
:ticket-filter-params="ticketFilterParams"
|
||||
@@ -42,12 +44,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
import { ref, computed, onMounted, reactive } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// Types
|
||||
import { TicketSimple, Motive, TicketFilterParams } from "../../types";
|
||||
import type { Person } from "ChillPersonAssets/types";
|
||||
import { Center } from "ChillMainAssets/types";
|
||||
|
||||
// Components
|
||||
import TicketListComponent from "./components/TicketListComponent.vue";
|
||||
@@ -55,8 +59,13 @@ import TicketFilterListComponent from "./components/TicketFilterListComponent.vu
|
||||
import { Pagination } from "ChillMainAssets/lib/api/apiMethods";
|
||||
|
||||
// Translations
|
||||
import { trans, CHILL_TICKET_LIST_LOADING_TICKET } from "translator";
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_LIST_LOADING_TICKET,
|
||||
CHILL_TICKET_LIST_UPDATED,
|
||||
} from "translator";
|
||||
|
||||
const toast = useToast();
|
||||
const store = useStore();
|
||||
const ticketFilterParams = window.ticketFilterParams
|
||||
? window.ticketFilterParams
|
||||
@@ -67,14 +76,45 @@ const ticketList = computed(
|
||||
() => store.getters.getTicketList as TicketSimple[],
|
||||
);
|
||||
const resultCount = computed(() => store.getters.getCount as number);
|
||||
const latestUpdate = computed(
|
||||
() => store.getters.getLatestUpdate as Date | null,
|
||||
);
|
||||
const pagination = computed(() => store.getters.getPagination as Pagination);
|
||||
const availablePersons = ref<Person[]>([]);
|
||||
const availableMotives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const availableCenters = computed(() => store.getters.getCenters as Center[]);
|
||||
const filters: TicketFilterParams = reactive({
|
||||
byPersonCenter: ticketFilterParams?.byPersonCenter
|
||||
? ticketFilterParams.byPersonCenter.map((person) => person.id)
|
||||
: [],
|
||||
byPerson: ticketFilterParams?.byPerson
|
||||
? ticketFilterParams.byPerson.map((person) => person.id)
|
||||
: [],
|
||||
byCreator: ticketFilterParams?.byCreator
|
||||
? ticketFilterParams.byCreator.map((creator) => creator.id)
|
||||
: [],
|
||||
byAddressee: ticketFilterParams?.byAddressee
|
||||
? ticketFilterParams.byAddressee.map((addressee) => addressee.id)
|
||||
: [],
|
||||
byCurrentState: ticketFilterParams?.byCurrentState ?? ["open"],
|
||||
byCurrentStateEmergency: ticketFilterParams?.byCurrentStateEmergency ?? [],
|
||||
byMotives: ticketFilterParams?.byMotives
|
||||
? ticketFilterParams.byMotives.map((motive) => motive.id)
|
||||
: [],
|
||||
byCreatedAfter: ticketFilterParams?.byCreatedAfter ?? "",
|
||||
byCreatedBefore: ticketFilterParams?.byCreatedBefore ?? "",
|
||||
byResponseTimeExceeded: ticketFilterParams?.byResponseTimeExceeded
|
||||
? "true"
|
||||
: "",
|
||||
byAddresseeToMe: ticketFilterParams?.byAddresseeToMe ?? false,
|
||||
byTicketId: ticketFilterParams?.byTicketId ?? null,
|
||||
});
|
||||
|
||||
const handleFiltersChanged = async (filters: TicketFilterParams) => {
|
||||
const handleFiltersChanged = async (ticketFilterParams: TicketFilterParams) => {
|
||||
isLoading.value = true;
|
||||
Object.assign(filters, ticketFilterParams);
|
||||
try {
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
await store.dispatch("fetchTicketList", ticketFilterParams);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -88,37 +128,21 @@ const fetchNextPage = async () => {
|
||||
|
||||
onMounted(async () => {
|
||||
isLoading.value = true;
|
||||
const filters: TicketFilterParams = {
|
||||
byPerson: ticketFilterParams?.byPerson
|
||||
? ticketFilterParams.byPerson.map((person) => person.id)
|
||||
: [],
|
||||
byCreator: ticketFilterParams?.byCreator
|
||||
? ticketFilterParams.byCreator.map((creator) => creator.id)
|
||||
: [],
|
||||
byAddressee: ticketFilterParams?.byAddressee
|
||||
? ticketFilterParams.byAddressee.map((addressee) => addressee.id)
|
||||
: [],
|
||||
byCurrentState: ticketFilterParams?.byCurrentState ?? ["open"],
|
||||
byCurrentStateEmergency: ticketFilterParams?.byCurrentStateEmergency ?? [],
|
||||
byMotives: ticketFilterParams?.byMotives
|
||||
? ticketFilterParams.byMotives.map((motive) => motive.id)
|
||||
: [],
|
||||
byCreatedAfter: ticketFilterParams?.byCreatedAfter ?? "",
|
||||
byCreatedBefore: ticketFilterParams?.byCreatedBefore ?? "",
|
||||
byResponseTimeExceeded: ticketFilterParams?.byResponseTimeExceeded
|
||||
? "true"
|
||||
: "",
|
||||
byAddresseeToMe: ticketFilterParams?.byAddresseeToMe ?? false,
|
||||
byTicketId: ticketFilterParams?.byTicketId ?? null,
|
||||
};
|
||||
|
||||
try {
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
store.dispatch("getCurrentUser");
|
||||
store.dispatch("fetchMotives");
|
||||
store.dispatch("fetchCenters");
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(async () => {
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
toast.success(trans(CHILL_TICKET_LIST_UPDATED));
|
||||
}, 60000);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="input-group mb-2">
|
||||
<vue-multiselect
|
||||
name="selectPersonCenter"
|
||||
id="selectPersonCenter"
|
||||
label="displayLabel"
|
||||
track-by="id"
|
||||
:custom-label="(value: Center) => value.name"
|
||||
:open-direction="openDirection"
|
||||
:multiple="true"
|
||||
:placeholder="trans(CHILL_TICKET_TICKET_SET_PERSON_CENTER_LABEL)"
|
||||
:options="centers"
|
||||
v-model="selectedCenter"
|
||||
class="form-control"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { Center } from "ChillMainAssets/types";
|
||||
import { trans, CHILL_TICKET_TICKET_SET_PERSON_CENTER_LABEL } from "translator";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object as () => Center[] | null,
|
||||
default: null,
|
||||
},
|
||||
centers: {
|
||||
type: Array as () => Center[],
|
||||
default: () => [],
|
||||
},
|
||||
openDirection: {
|
||||
type: String,
|
||||
default: "bottom",
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: Center[] | null) => void>();
|
||||
|
||||
const selectedCenter = computed<Center[] | null>({
|
||||
get() {
|
||||
return props.modelValue;
|
||||
},
|
||||
set(value: Center[] | null) {
|
||||
emit("update:modelValue", value);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-control {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep .multiselect__tag {
|
||||
background: var(--bs-chill-green) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
@@ -52,38 +52,16 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<!-- Filtre par motifs -->
|
||||
<div class="row">
|
||||
<label class="form-label" for="motiveSelector">{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_BY_MOTIVES)
|
||||
}}</label>
|
||||
<motive-selector
|
||||
v-model="selectedMotive"
|
||||
:motives="availableMotives"
|
||||
:allow-parent-selection="true"
|
||||
@remove="(motive) => removeMotive(motive)"
|
||||
id="motiveSelector"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
<label class="form-label" for="personCenterSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_PERSON_CENTER) }}
|
||||
</label>
|
||||
<person-center-selector-component
|
||||
v-model="selectedPersonCenter"
|
||||
:centers="availableCenters"
|
||||
id="personCenterSelector"
|
||||
:disabled="ticketFilterParams?.byPersonCenter ? true : false"
|
||||
/>
|
||||
|
||||
<div class="mb-2" style="min-height: 2em">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="motive in filters.byMotives"
|
||||
:key="motive.id"
|
||||
class="badge bg-secondary d-flex align-items-center gap-1"
|
||||
>
|
||||
{{ getMotiveDisplayName(motive) }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close btn-close-white"
|
||||
:aria-label="trans(CHILL_TICKET_LIST_FILTER_REMOVE)"
|
||||
@click="removeMotive(motive)"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Filtre par état actuel -->
|
||||
<div class="d-flex gap-3">
|
||||
@@ -167,14 +145,50 @@
|
||||
</div>
|
||||
<!-- Filtre par numéro de ticket -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label pe-2" for="ticketSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_TICKET_ID) }}
|
||||
</label>
|
||||
<ticket-selector
|
||||
v-model="filters.byTicketId"
|
||||
id="ticketSelector"
|
||||
:disabled="ticketFilterParams?.byTicketId ? true : false"
|
||||
/>
|
||||
<div class="row">
|
||||
<label class="form-label pe-2" for="ticketSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_TICKET_ID) }}
|
||||
</label>
|
||||
<ticket-selector
|
||||
v-model="filters.byTicketId"
|
||||
id="ticketSelector"
|
||||
:disabled="ticketFilterParams?.byTicketId ? true : false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Filtre par motifs -->
|
||||
<div class="row">
|
||||
<label class="form-label" for="motiveSelector">{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_BY_MOTIVES)
|
||||
}}</label>
|
||||
<motive-selector
|
||||
v-model="selectedMotive"
|
||||
:motives="availableMotives"
|
||||
:allow-parent-selection="true"
|
||||
@remove="(motive) => removeMotive(motive)"
|
||||
id="motiveSelector"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
/>
|
||||
|
||||
<div class="mb-2" style="min-height: 2em">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="motive in filters.byMotives"
|
||||
:key="motive.id"
|
||||
class="badge bg-secondary d-flex align-items-center gap-1"
|
||||
>
|
||||
{{ getMotiveDisplayName(motive) }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close btn-close-white"
|
||||
:aria-label="trans(CHILL_TICKET_LIST_FILTER_REMOVE)"
|
||||
@click="removeMotive(motive)"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -234,11 +248,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span
|
||||
class="col-12 d-flex align-items-end justify-content-end form-text text-muted mt-1"
|
||||
v-if="latestUpdate"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
class="col-12 d-flex align-items-end justify-content-end form-text text-muted mt-1"
|
||||
>
|
||||
{{ resultCount !== 0 ? `${resultCount} ` : "" }}
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_RESULT, { count: resultCount }) }}
|
||||
<span v-if="latestUpdate">
|
||||
{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_AT_TIME, {
|
||||
date: latestUpdate.toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
}),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
@@ -248,6 +278,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Center } from "ChillMainAssets/types";
|
||||
import type { Person } from "ChillPersonAssets/types";
|
||||
import {
|
||||
type Motive,
|
||||
@@ -263,6 +294,7 @@ import {
|
||||
CHILL_TICKET_LIST_FILTER_BY_PERSON,
|
||||
CHILL_TICKET_LIST_FILTER_CREATORS,
|
||||
CHILL_TICKET_LIST_FILTER_BY_CREATOR,
|
||||
CHILL_TICKET_LIST_FILTER_BY_PERSON_CENTER,
|
||||
CHILL_TICKET_LIST_FILTER_ADDRESSEES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_ADDRESSEES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_MOTIVES,
|
||||
@@ -280,21 +312,26 @@ import {
|
||||
CHILL_TICKET_LIST_FILTER_APPLY,
|
||||
CHILL_TICKET_LIST_FILTER_RESULT,
|
||||
CHILL_TICKET_LIST_FILTER_CURRENT_STATE,
|
||||
CHILL_TICKET_LIST_FILTER_AT_TIME,
|
||||
} from "translator";
|
||||
|
||||
// Components
|
||||
import PersonsSelector from "../../TicketApp/components/Person/PersonsSelectorComponent.vue";
|
||||
import MotiveSelector from "../../TicketApp/components/Motive/MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "../../TicketApp/components/Addressee/AddresseeSelectorComponent.vue";
|
||||
|
||||
import ToggleComponent from "./ToggleComponent.vue";
|
||||
import TicketSelector from "../../TicketApp/components/Ticket/TicketSelector.vue";
|
||||
import DateAndTimeSelectorComponent from "./DateAndTimeSelectorComponent.vue";
|
||||
import PersonCenterSelectorComponent from "./PersonCenterSelectorComponent.vue";
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
availableCenters: Center[];
|
||||
availablePersons?: Person[];
|
||||
availableMotives: Motive[];
|
||||
resultCount: number;
|
||||
latestUpdate: Date | null;
|
||||
ticketFilterParams: TicketFilters | null;
|
||||
}>();
|
||||
|
||||
@@ -304,6 +341,7 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const filtersInitValues: TicketFilters = {
|
||||
byPersonCenter: props.ticketFilterParams?.byPersonCenter ?? [],
|
||||
byPerson: props.ticketFilterParams?.byPerson ?? [],
|
||||
byCreator: props.ticketFilterParams?.byCreator ?? [],
|
||||
byAddressee: props.ticketFilterParams?.byAddressee ?? [],
|
||||
@@ -328,6 +366,13 @@ const isClosedToggled = ref(false);
|
||||
const isEmergencyToggled = ref(false);
|
||||
|
||||
const availablePersons = ref<Person[]>(props.availablePersons || []);
|
||||
|
||||
const selectedPersonCenter = ref<Center[] | null>(null);
|
||||
|
||||
watch(selectedPersonCenter, (newPersonCenter) => {
|
||||
filters.value.byPersonCenter = newPersonCenter ?? [];
|
||||
});
|
||||
|
||||
const selectedMotive = ref<Motive | null>();
|
||||
|
||||
watch(selectedMotive, (newMotive) => {
|
||||
@@ -363,6 +408,10 @@ const selectedMotiveIds = computed(() =>
|
||||
filters.value.byMotives.map((motive) => motive.id),
|
||||
);
|
||||
|
||||
const selectedPersonCenterIds = computed(() =>
|
||||
filters.value.byPersonCenter.map((center) => center.id),
|
||||
);
|
||||
|
||||
const handleStateToggle = (value: boolean) => {
|
||||
if (value) {
|
||||
filters.value.byCurrentState = ["closed"];
|
||||
@@ -433,6 +482,10 @@ const applyFilters = (): void => {
|
||||
apiFilters.byMotives = selectedMotiveIds.value;
|
||||
}
|
||||
|
||||
if (selectedPersonCenterIds.value.length > 0) {
|
||||
apiFilters.byPersonCenter = selectedPersonCenterIds.value;
|
||||
}
|
||||
|
||||
if (filters.value.byCreatedAfter) {
|
||||
apiFilters.byCreatedAfter = formatDateToISO(
|
||||
filters.value.byCreatedAfter,
|
||||
|
||||
@@ -43,26 +43,26 @@
|
||||
|
||||
<div class="card-body pt-0">
|
||||
<div class="row" v-if="ticket.currentAddressees.length">
|
||||
<div class="col-12 title text-start">
|
||||
<div class="col-md-3 col-12 title text-start" style="max-width: 215px">
|
||||
<h3>{{ trans(CHILL_TICKET_LIST_ADDRESSEES) }}</h3>
|
||||
</div>
|
||||
<div class="col-12 list">
|
||||
<div class="col-md-9 col-12 list">
|
||||
<addressee-component :addressees="ticket.currentAddressees" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="ticket.currentPersons.length">
|
||||
<div class="col-12 title text-start">
|
||||
<div class="col-md-3 col-12 title text-start" style="max-width: 215px">
|
||||
<h3>{{ trans(CHILL_TICKET_LIST_PERSONS) }}</h3>
|
||||
</div>
|
||||
<div class="col-12 list">
|
||||
<div class="col-md-9 col-12 list">
|
||||
<person-component :entities="ticket.currentPersons" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="ticket.caller">
|
||||
<div class="col-12 title text-start">
|
||||
<div class="col-md-3 col-12 title text-start" style="max-width: 215px">
|
||||
<h3>{{ trans(CHILL_TICKET_LIST_CALLERS) }}</h3>
|
||||
</div>
|
||||
<div class="col-12 list">
|
||||
<div class="col-md-9 col-12 list">
|
||||
<person-component
|
||||
:entities="
|
||||
ticket.caller ? ([ticket.caller] as Person[] | Thirdparty[]) : []
|
||||
|
||||
@@ -142,7 +142,7 @@ final readonly class ImportMotivesFromDirectory
|
||||
// Support parent > child notation in the current language label
|
||||
$parentName = null;
|
||||
$childName = trim($labelForSearch);
|
||||
if (str_contains($childName, '>')) {
|
||||
if (false !== strpos($childName, '>')) {
|
||||
[$parentName, $childName] = array_map('trim', explode('>', $childName, 2));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ chill_ticket:
|
||||
loading_ticket: "Chargement des tickets..."
|
||||
loading_ticket_details: "Chargement de l'historique du ticket..."
|
||||
error_loading_ticket: "Erreur lors du chargement des ticket"
|
||||
updated: "Liste des tickets mise à jour"
|
||||
load_more: "Voir plus..."
|
||||
addressees: "Destinataires"
|
||||
persons: "Usager concernés"
|
||||
@@ -24,6 +25,7 @@ chill_ticket:
|
||||
by_person: "Par personne"
|
||||
creators: "Créateurs"
|
||||
by_creator: "Par créateur"
|
||||
by_person_center: "Par unité"
|
||||
addressees: "Par destinataire"
|
||||
by_addressees: "Par destinataire"
|
||||
by_motives: "Par motifs"
|
||||
@@ -42,7 +44,7 @@ chill_ticket:
|
||||
apply: "Appliquer les filtres"
|
||||
remove: "Supprimer"
|
||||
result: "{count, plural, =0 {Aucun résultat} =1 {resultat} other {resultats}}"
|
||||
|
||||
at_time: "à {date}"
|
||||
ticket:
|
||||
init_form:
|
||||
title: "Ajouter des informations sur le ticket"
|
||||
@@ -103,6 +105,8 @@ chill_ticket:
|
||||
caller_label: "Ajouter un appelant"
|
||||
success: "Appelants et usagers mis à jour"
|
||||
error: "Aucun usager sélectionné"
|
||||
set_person_center:
|
||||
label: "Choisir une unité"
|
||||
banner:
|
||||
person: "{count, plural, =0 {Aucun usager impliqué} =1 {Usager impliqué} other {Usagers impliqués}}"
|
||||
speaker: "{count, plural, =0 {Aucun destinataire} =1 {Destinataire} other {Destinataires}}"
|
||||
|
||||
Reference in New Issue
Block a user