mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-11-10 06:08:25 +00:00
Améliorer l'affichage de la hiérarchie des motifs et ajouter une checkbox « Afficher uniquement les commentaires ».
This commit is contained in:
@@ -175,8 +175,6 @@ async function download_and_decrypt_doc(
|
|||||||
throw new Error("no version associated to stored object");
|
throw new Error("no version associated to stored object");
|
||||||
}
|
}
|
||||||
|
|
||||||
// sometimes, the downloadInfo may be embedded into the storedObject
|
|
||||||
console.log("storedObject", storedObject);
|
|
||||||
let downloadInfo;
|
let downloadInfo;
|
||||||
if (
|
if (
|
||||||
typeof storedObject._links !== "undefined" &&
|
typeof storedObject._links !== "undefined" &&
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ use Chill\TicketBundle\Messenger\PostTicketUpdateMessage;
|
|||||||
use Chill\TicketBundle\Repository\TicketRepositoryInterface;
|
use Chill\TicketBundle\Repository\TicketRepositoryInterface;
|
||||||
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
|
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
|
|
||||||
|
#[AsMessageHandler]
|
||||||
final readonly class PostTicketUpdateMessageHandler
|
final readonly class PostTicketUpdateMessageHandler
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface MotiveBase {
|
|||||||
id: number;
|
id: number;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
label: TranslatableString;
|
label: TranslatableString;
|
||||||
|
makeTicketEmergency: TicketEmergencyState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<banner-component :ticket="ticket" />
|
<banner-component :ticket="ticket" />
|
||||||
<div class="container-xxl pt-1" style="padding-bottom: 55px" v-if="!loading">
|
<div class="container-xxl pt-1" style="padding-bottom: 55px" v-if="!loading">
|
||||||
<previous-tickets-component :key="refreshKey" />
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
v-model="showOnlyHistoryComments"
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="showOnlyCommentsCheckbox"
|
||||||
|
/>
|
||||||
|
<label class="form-check-label" for="showOnlyCommentsCheckbox">
|
||||||
|
{{ trans(CHILL_TICKET_LIST_SHOW_ONLY_HISTORY_COMMENTS) }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col d-flex justify-content-end">
|
||||||
|
<previous-tickets-component :key="refreshKey" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<ticket-history-list-component
|
<ticket-history-list-component
|
||||||
:history="ticketHistory"
|
:history="ticketHistory"
|
||||||
:key="ticketHistory.length"
|
:key="ticketHistory.length"
|
||||||
@@ -64,15 +81,20 @@ import {
|
|||||||
CHILL_TICKET_TICKET_INIT_FORM_ERROR,
|
CHILL_TICKET_TICKET_INIT_FORM_ERROR,
|
||||||
CHILL_TICKET_TICKET_INIT_FORM_WARNING,
|
CHILL_TICKET_TICKET_INIT_FORM_WARNING,
|
||||||
CHILL_TICKET_LIST_LOADING_TICKET_DETAILS,
|
CHILL_TICKET_LIST_LOADING_TICKET_DETAILS,
|
||||||
|
CHILL_TICKET_LIST_SHOW_ONLY_HISTORY_COMMENTS,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
store.commit("setTicket", JSON.parse(window.initialTicket) as Ticket);
|
store.commit("setTicket", JSON.parse(window.initialTicket) as Ticket);
|
||||||
|
const showOnlyHistoryComments = ref(false);
|
||||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||||
const ticketHistory = computed(() => store.getters.getTicketHistory);
|
const ticketHistory = computed(() =>
|
||||||
|
showOnlyHistoryComments.value
|
||||||
|
? store.getters.getTicketHistoryComments
|
||||||
|
: store.getters.getTicketHistory,
|
||||||
|
);
|
||||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||||
const suggestedPersons = computed(() => store.getters.getPersons as Person[]);
|
const suggestedPersons = computed(() => store.getters.getPersons as Person[]);
|
||||||
const showTicketInitFormModal = ref(false);
|
const showTicketInitFormModal = ref(false);
|
||||||
@@ -81,21 +103,22 @@ const refreshKey = ref(0);
|
|||||||
|
|
||||||
async function handleFormSubmit(ticketForm: TicketInitForm) {
|
async function handleFormSubmit(ticketForm: TicketInitForm) {
|
||||||
try {
|
try {
|
||||||
|
if (!ticketForm.motive || ticketForm.content.trim() === "") {
|
||||||
|
toast.warning(trans(CHILL_TICKET_TICKET_INIT_FORM_WARNING));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ticketForm.motive) {
|
if (ticketForm.motive) {
|
||||||
await store.dispatch("createMotive", ticketForm.motive);
|
await store.dispatch("createMotive", ticketForm.motive);
|
||||||
} else {
|
|
||||||
toast.warning(trans(CHILL_TICKET_TICKET_INIT_FORM_WARNING));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (ticketForm.content.trim() !== "") {
|
||||||
if (ticketForm.content && ticketForm.content.trim() !== "") {
|
|
||||||
await store.dispatch("createComment", ticketForm.content);
|
await store.dispatch("createComment", ticketForm.content);
|
||||||
} else {
|
|
||||||
toast.warning(trans(CHILL_TICKET_TICKET_INIT_FORM_WARNING));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await store.dispatch("setEmergency", ticketForm.emergency);
|
// Ne pas mettre à jour emergency si le motif force l'état d'urgence
|
||||||
|
if (ticketForm.motive && !ticketForm.motive.makeTicketEmergency) {
|
||||||
|
await store.dispatch("setEmergency", ticketForm.emergency);
|
||||||
|
}
|
||||||
|
|
||||||
await store.dispatch("setAddressees", ticketForm.addressees);
|
await store.dispatch("setAddressees", ticketForm.addressees);
|
||||||
await store.dispatch("setPersons", ticketForm.persons);
|
await store.dispatch("setPersons", ticketForm.persons);
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function addNewEntity({ entity }: { entity: EntitiesOrMe }) {
|
|||||||
|
|
||||||
function removeEntity({ entity }: { entity: EntitiesOrMe }) {
|
function removeEntity({ entity }: { entity: EntitiesOrMe }) {
|
||||||
const index = selectedEntities.value.findIndex(
|
const index = selectedEntities.value.findIndex(
|
||||||
(selectedEntity) => selectedEntity === entity,
|
(selectedEntity: Entities) => selectedEntity === entity,
|
||||||
);
|
);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
selectedEntities.value.splice(index, 1);
|
selectedEntities.value.splice(index, 1);
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
<div class="container-xxl text-primary">
|
<div class="container-xxl text-primary">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
|
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
|
||||||
|
<div class="small text-muted">
|
||||||
|
{{ motiveHierarchyLabel(ticket.currentMotive) }}
|
||||||
|
</div>
|
||||||
<h1>
|
<h1>
|
||||||
{{ getTicketTitle(ticket) }}
|
{{ getTicketTitle(ticket) }}
|
||||||
<peloton-component
|
<peloton-component
|
||||||
@@ -26,7 +29,7 @@
|
|||||||
<state-toggle-component v-model="isOpen" />
|
<state-toggle-component v-model="isOpen" />
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
<p class="created-at-timespan" v-if="ticket.createdAt">
|
<p class="created-at-timespan" v-if="since">
|
||||||
{{
|
{{
|
||||||
trans(CHILL_TICKET_TICKET_BANNER_SINCE, {
|
trans(CHILL_TICKET_TICKET_BANNER_SINCE, {
|
||||||
time: since,
|
time: since,
|
||||||
@@ -127,7 +130,7 @@ import {
|
|||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { getTicketTitle } from "../utils/utils";
|
import { getTicketTitle, motiveHierarchyLabel } from "../utils/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
ticket: Ticket;
|
ticket: Ticket;
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="col-12 fw-bolder">
|
<div class="col-12">
|
||||||
{{ motiveLabelRecursive(props.motiveHistory.motive) }}
|
<span class="badge-motive">
|
||||||
|
<div>
|
||||||
|
{{ localizeString(props.motiveHistory.motive.label) }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
<peloton-component
|
<peloton-component
|
||||||
:stored-objects="motive ? motive.storedObjects : null"
|
:stored-objects="motive ? motive.storedObjects : null"
|
||||||
pelotonBtnClass="float-end"
|
pelotonBtnClass="float-end"
|
||||||
@@ -9,17 +13,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed, ComputedRef } from "vue";
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
// Types
|
|
||||||
import {Motive, MotiveHistory, MotiveWithParent} from "../../../../types";
|
|
||||||
|
|
||||||
//Utils
|
//utils
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import { Motive, MotiveHistory } from "../../../../types";
|
||||||
|
|
||||||
//Components
|
//Components
|
||||||
import PelotonComponent from "../PelotonComponent.vue";
|
import PelotonComponent from "../PelotonComponent.vue";
|
||||||
import { computed, ComputedRef } from "vue";
|
|
||||||
import {motiveLabelRecursive} from "../../utils/utils";
|
|
||||||
|
|
||||||
const props = defineProps<{ motiveHistory: MotiveHistory }>();
|
const props = defineProps<{ motiveHistory: MotiveHistory }>();
|
||||||
|
|
||||||
@@ -29,4 +33,18 @@ const motive: ComputedRef<Motive | null> = computed(() =>
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped>
|
||||||
|
span.badge-motive {
|
||||||
|
margin: 0.2rem 0.1rem;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 0.5em !important;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #2c2d2f;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -11,11 +11,14 @@
|
|||||||
:open-direction="openDirection"
|
:open-direction="openDirection"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
|
:internalSearch="false"
|
||||||
:placeholder="trans(CHILL_TICKET_TICKET_SET_MOTIVE_LABEL)"
|
:placeholder="trans(CHILL_TICKET_TICKET_SET_MOTIVE_LABEL)"
|
||||||
:options="flattenedMotives"
|
:options="options"
|
||||||
|
:loading="isLoading"
|
||||||
v-model="motive"
|
v-model="motive"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
@remove="(value: Motive) => $emit('remove', value)"
|
@remove="(value: Motive) => $emit('remove', value)"
|
||||||
|
@search-change="search"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
@@ -57,7 +60,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import VueMultiselect from "vue-multiselect";
|
import VueMultiselect from "vue-multiselect";
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
@@ -116,50 +119,73 @@ const motive = computed<Motive | null>({
|
|||||||
emit("update:modelValue", value);
|
emit("update:modelValue", value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
type MotiveOptions = Motive & {
|
||||||
|
isChild?: boolean;
|
||||||
|
isParent?: boolean;
|
||||||
|
level?: number;
|
||||||
|
displayLabel: string;
|
||||||
|
breadcrumb: string[];
|
||||||
|
};
|
||||||
|
|
||||||
const flattenedMotives = computed(() => {
|
const motiveOptions: MotiveOptions[] = [];
|
||||||
const result: (Motive & {
|
const options = ref<MotiveOptions[]>([]);
|
||||||
isChild?: boolean;
|
const isLoading = ref<boolean>(false);
|
||||||
isParent?: boolean;
|
|
||||||
level?: number;
|
|
||||||
displayLabel: string;
|
|
||||||
breadcrumb: string[];
|
|
||||||
})[] = [];
|
|
||||||
|
|
||||||
const processMotiveRecursively = (
|
function search(query: string) {
|
||||||
motive: Motive,
|
isLoading.value = true;
|
||||||
isChild = false,
|
options.value = motiveOptions.filter((m) =>
|
||||||
level = 0,
|
m.breadcrumb.some((crumb) =>
|
||||||
parentBreadcrumb: string[] = [],
|
crumb.toLowerCase().includes(query.trim().toLowerCase()),
|
||||||
) => {
|
),
|
||||||
const hasChildren = motive.children && motive.children.length > 0;
|
);
|
||||||
const displayLabel = localizeString(motive.label);
|
isLoading.value = false;
|
||||||
const breadcrumb = [...parentBreadcrumb, displayLabel];
|
}
|
||||||
|
|
||||||
if (props.allowParentSelection || !hasChildren) {
|
function processMotiveRecursively(
|
||||||
result.push({
|
motive: Motive,
|
||||||
...motive,
|
isChild = false,
|
||||||
isChild,
|
level = 0,
|
||||||
isParent: hasChildren,
|
parentBreadcrumb: string[] = [],
|
||||||
level,
|
) {
|
||||||
breadcrumb,
|
const hasChildren = motive.children && motive.children.length > 0;
|
||||||
displayLabel,
|
const displayLabel = localizeString(motive.label);
|
||||||
});
|
const breadcrumb = [...parentBreadcrumb, displayLabel];
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChildren) {
|
if (props.allowParentSelection || !hasChildren) {
|
||||||
motive.children.forEach((childMotive) => {
|
const optionValue = {
|
||||||
processMotiveRecursively(childMotive, true, level + 1, breadcrumb);
|
...motive,
|
||||||
});
|
isChild,
|
||||||
}
|
isParent: hasChildren,
|
||||||
};
|
level,
|
||||||
|
breadcrumb,
|
||||||
|
displayLabel,
|
||||||
|
};
|
||||||
|
motiveOptions.push(optionValue);
|
||||||
|
options.value.push(optionValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChildren) {
|
||||||
|
motive.children.forEach((childMotive) => {
|
||||||
|
processMotiveRecursively(childMotive, true, level + 1, breadcrumb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillOptions() {
|
||||||
|
motiveOptions.length = 0;
|
||||||
|
options.value.length = 0;
|
||||||
props.motives.forEach((parentMotive) => {
|
props.motives.forEach((parentMotive) => {
|
||||||
processMotiveRecursively(parentMotive, false, 0, []);
|
processMotiveRecursively(parentMotive, false, 0, []);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
watch(
|
||||||
});
|
() => props.motives,
|
||||||
|
() => {
|
||||||
|
fillOptions();
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ function addNewEntity({ entity }: { entity: EntitiesOrMe }) {
|
|||||||
function removeEntity({ entity }: { entity: EntitiesOrMe }) {
|
function removeEntity({ entity }: { entity: EntitiesOrMe }) {
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
const index = selectedEntities.value.findIndex(
|
const index = selectedEntities.value.findIndex(
|
||||||
(selectedEntity) => selectedEntity === entity,
|
(selectedEntity: Entities) => selectedEntity === entity,
|
||||||
);
|
);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
selectedEntities.value.splice(index, 1);
|
selectedEntities.value.splice(index, 1);
|
||||||
|
|||||||
@@ -1,52 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="d-flex justify-content-end">
|
<div @click="handleClick">
|
||||||
<div @click="handleClick">
|
<button type="button" class="btn btn-light position-relative">
|
||||||
<button type="button" class="btn btn-light position-relative">
|
{{ trans(CHILL_TICKET_TICKET_PREVIOUS_TICKETS) }}
|
||||||
{{ trans(CHILL_TICKET_TICKET_PREVIOUS_TICKETS) }}
|
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-chill-green"
|
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-chill-green"
|
||||||
>
|
>
|
||||||
{{ previousTickets.length }}
|
{{ previousTickets.length }}
|
||||||
<span class="visually-hidden">Tickets</span>
|
<span class="visually-hidden">Tickets</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal for ticket list -->
|
|
||||||
<Modal
|
|
||||||
v-if="showPreviousTicketModal"
|
|
||||||
:show="showPreviousTicketModal"
|
|
||||||
modal-dialog-class="modal-lg"
|
|
||||||
@close="closeModal"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<h3 class="modal-title">
|
|
||||||
{{
|
|
||||||
trans(CHILL_TICKET_LIST_TITLE_PREVIOUS_TICKETS, {
|
|
||||||
name:
|
|
||||||
currentPersons.length > 0
|
|
||||||
? currentPersons
|
|
||||||
.map((person: Person) => person.text)
|
|
||||||
.join(", ")
|
|
||||||
: undefined,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</h3>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #body>
|
|
||||||
<ticket-list-component
|
|
||||||
:hasMoreTickets="pagination.next !== null"
|
|
||||||
:tickets="previousTickets"
|
|
||||||
:title="trans(CHILL_TICKET_LIST_NO_TICKETS)"
|
|
||||||
@fetchNextPage="fetchNextPage"
|
|
||||||
@view-ticket="handleViewTicket"
|
|
||||||
@edit-ticket="handleEditTicket"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal for ticket list -->
|
||||||
|
<Modal
|
||||||
|
v-if="showPreviousTicketModal"
|
||||||
|
:show="showPreviousTicketModal"
|
||||||
|
modal-dialog-class="modal-lg"
|
||||||
|
@close="closeModal"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<h3 class="modal-title">
|
||||||
|
{{
|
||||||
|
trans(CHILL_TICKET_LIST_TITLE_PREVIOUS_TICKETS, {
|
||||||
|
name:
|
||||||
|
currentPersons.length > 0
|
||||||
|
? currentPersons.map((person: Person) => person.text).join(", ")
|
||||||
|
: undefined,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</h3>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body>
|
||||||
|
<ticket-list-component
|
||||||
|
:hasMoreTickets="pagination.next !== null"
|
||||||
|
:tickets="previousTickets"
|
||||||
|
:title="trans(CHILL_TICKET_LIST_NO_TICKETS)"
|
||||||
|
@fetchNextPage="fetchNextPage"
|
||||||
|
@view-ticket="handleViewTicket"
|
||||||
|
@edit-ticket="handleEditTicket"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export interface RootState {
|
|||||||
user: UserState;
|
user: UserState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const store = createStore<RootState>({
|
export const store = createStore({
|
||||||
modules: {
|
modules: {
|
||||||
motive: moduleMotive,
|
motive: moduleMotive,
|
||||||
ticket: moduleTicket,
|
ticket: moduleTicket,
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import {
|
|||||||
makeFetch,
|
makeFetch,
|
||||||
} from "../../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
} from "../../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
||||||
|
|
||||||
import { Module } from "vuex";
|
import type { RootState } from "..";
|
||||||
import { RootState } from "..";
|
import type { Module } from "vuex";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ApiException,
|
ApiException,
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ export const moduleTicket: Module<State, RootState> = {
|
|||||||
getTicketHistory: (state) => {
|
getTicketHistory: (state) => {
|
||||||
return state.ticket.history;
|
return state.ticket.history;
|
||||||
},
|
},
|
||||||
|
getTicketHistoryComments: (state) => {
|
||||||
|
return state.ticket.history.filter(
|
||||||
|
(history) => history.event_type == "add_comment",
|
||||||
|
);
|
||||||
|
},
|
||||||
getCurrentPersons(state) {
|
getCurrentPersons(state) {
|
||||||
return state.ticket.currentPersons;
|
return state.ticket.currentPersons;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
CHILL_TICKET_TICKET_BANNER_AND,
|
CHILL_TICKET_TICKET_BANNER_AND,
|
||||||
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
|
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
import {MotiveWithParent, Ticket, TicketSimple} from "../../../types";
|
import { MotiveWithParent, Ticket, TicketSimple } from "../../../types";
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,8 +18,11 @@ import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizat
|
|||||||
* @returns Une chaîne formatée représentant le temps écoulé
|
* @returns Une chaîne formatée représentant le temps écoulé
|
||||||
*/
|
*/
|
||||||
export function getSinceCreated(createdAt: string, currentTime: Date): string {
|
export function getSinceCreated(createdAt: string, currentTime: Date): string {
|
||||||
|
if (!createdAt) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
const date = ISOToDatetime(createdAt);
|
const date = ISOToDatetime(createdAt);
|
||||||
if (date == null) {
|
if (!date) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +32,6 @@ export function getSinceCreated(createdAt: string, currentTime: Date): string {
|
|||||||
const minutesDiff = Math.floor((timeDiff % (1000 * 3600)) / (1000 * 60));
|
const minutesDiff = Math.floor((timeDiff % (1000 * 3600)) / (1000 * 60));
|
||||||
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000);
|
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000);
|
||||||
|
|
||||||
// On construit la liste des parties à afficher
|
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
if (daysDiff > 0) {
|
if (daysDiff > 0) {
|
||||||
parts.push(trans(CHILL_TICKET_TICKET_BANNER_DAYS, { count: daysDiff }));
|
parts.push(trans(CHILL_TICKET_TICKET_BANNER_DAYS, { count: daysDiff }));
|
||||||
@@ -83,18 +85,19 @@ export function getTicketTitle(ticket: Ticket | TicketSimple): string {
|
|||||||
return `#${ticket.id} ${trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE)}`;
|
return `#${ticket.id} ${trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function motiveLabelRecursive(motive: MotiveWithParent|null): string {
|
export function motiveHierarchyLabel(motive: MotiveWithParent | null): string {
|
||||||
console.log('test', motive);
|
|
||||||
if (null === motive) {
|
if (null === motive) {
|
||||||
return "";
|
return "Aucun motif";
|
||||||
}
|
}
|
||||||
|
|
||||||
const str = [];
|
const str = [];
|
||||||
let m: MotiveWithParent|null = motive;
|
let m: MotiveWithParent | null = motive;
|
||||||
do {
|
do {
|
||||||
str.push(localizeString(m.label));
|
str.push(localizeString(m.label));
|
||||||
m = m.parent;
|
m = m.parent;
|
||||||
} while (m !== null);
|
} while (m !== null);
|
||||||
|
str.reverse();
|
||||||
return str.reverse().join(" > ");
|
if (str.length > 1) {
|
||||||
|
str.pop();
|
||||||
|
}
|
||||||
|
return str.join(" > ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,11 @@
|
|||||||
<div class="card mb-3 text-primary border-primary">
|
<div class="card mb-3 text-primary border-primary">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="wrap-header">
|
<div class="wrap-header">
|
||||||
<div class="wh-row d-flex justify-content-between align-items-center">
|
<div class="wh-row d-flex justify-content-between align-items-top">
|
||||||
<div class="wh-col">
|
<div v-if="null !== ticket.currentMotive && null !== ticket.currentMotive.parent" class="wh-col">
|
||||||
<span
|
<div class="small text-muted">
|
||||||
class="h2"
|
{{ motiveHierarchyLabel(ticket.currentMotive) }}
|
||||||
style="color: var(--bs-chill-blue); font-variant: all-small-caps"
|
</div>
|
||||||
>
|
|
||||||
{{ getTicketTitle(ticket) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="wh-col">
|
<div class="wh-col">
|
||||||
<emergency-component
|
<emergency-component
|
||||||
@@ -23,9 +20,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wh-row">
|
<div class="wh-row">
|
||||||
<div class="wh-col" v-if="ticket.createdAt">
|
<div class="wh-col">
|
||||||
<span
|
<span
|
||||||
v-if="ticket"
|
class="h2"
|
||||||
|
style="color: var(--bs-chill-blue); font-variant: all-small-caps"
|
||||||
|
>
|
||||||
|
{{ getTicketTitle(ticket) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="wh-col">
|
||||||
|
<span
|
||||||
|
v-if="ticket.createdAt"
|
||||||
:title="formatDateTime(ticket.createdAt.datetime, 'long', 'long')"
|
:title="formatDateTime(ticket.createdAt.datetime, 'long', 'long')"
|
||||||
style="font-style: italic"
|
style="font-style: italic"
|
||||||
>
|
>
|
||||||
@@ -105,6 +110,7 @@ import {
|
|||||||
getSinceCreated,
|
getSinceCreated,
|
||||||
formatDateTime,
|
formatDateTime,
|
||||||
getTicketTitle,
|
getTicketTitle,
|
||||||
|
motiveHierarchyLabel,
|
||||||
} from "../../TicketApp/utils/utils";
|
} from "../../TicketApp/utils/utils";
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ chill_ticket:
|
|||||||
title: "Tickets"
|
title: "Tickets"
|
||||||
title_with_name: "{name, select, null {Tickets} undefined {Tickets} other {Tickets de {name}}}"
|
title_with_name: "{name, select, null {Tickets} undefined {Tickets} other {Tickets de {name}}}"
|
||||||
title_menu: "Tickets de l'usager"
|
title_menu: "Tickets de l'usager"
|
||||||
|
show_only_history_comments: "Afficher uniquement les commentaires"
|
||||||
title_previous_tickets: "{name, select, other {Précédent ticket de {name}} undefined {Précédent ticket}}"
|
title_previous_tickets: "{name, select, other {Précédent ticket de {name}} undefined {Précédent ticket}}"
|
||||||
no_tickets: "Aucun ticket"
|
no_tickets: "Aucun ticket"
|
||||||
loading_ticket: "Chargement des tickets..."
|
loading_ticket: "Chargement des tickets..."
|
||||||
|
|||||||
3
src/shims-custom.d.ts
vendored
Normal file
3
src/shims-custom.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
declare module "vue-multiselect";
|
||||||
|
declare module "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||||
|
declare module "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||||
@@ -11,4 +11,9 @@
|
|||||||
"ChillPersonAssets/*": ["./src/Bundle/ChillPersonBundle/Resources/public/*"]
|
"ChillPersonAssets/*": ["./src/Bundle/ChillPersonBundle/Resources/public/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
"src/**/*.vue"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user