mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge remote-tracking branch 'origin/366-pick-user-or-me' into 339-partage-d'export-enregistré
This commit is contained in:
commit
8c59cbc6a0
3
.changes/v3.10.3.md
Normal file
3
.changes/v3.10.3.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## v3.10.3 - 2025-03-18
|
||||||
|
### DX
|
||||||
|
* Eslint fixes
|
@ -6,6 +6,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|||||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||||
|
|
||||||
|
|
||||||
|
## v3.10.3 - 2025-03-18
|
||||||
|
### DX
|
||||||
|
* Eslint fixes
|
||||||
|
|
||||||
## v3.10.2 - 2025-03-17
|
## v3.10.2 - 2025-03-17
|
||||||
### Fixed
|
### Fixed
|
||||||
* Replace a ts-expect-error with a ts-ignore
|
* Replace a ts-expect-error with a ts-ignore
|
||||||
|
@ -34,6 +34,7 @@ export default ts.config(
|
|||||||
// override/add rules settings here, such as:
|
// override/add rules settings here, such as:
|
||||||
"vue/multi-word-component-names": "off",
|
"vue/multi-word-component-names": "off",
|
||||||
"@typescript-eslint/no-require-imports": "off",
|
"@typescript-eslint/no-require-imports": "off",
|
||||||
|
"@typescript-eslint/ban-ts-comment": "off"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -66,8 +66,11 @@ class EntityToJsonTransformer implements DataTransformerInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function denormalizeOne(array $item)
|
private function denormalizeOne(array|string $item)
|
||||||
{
|
{
|
||||||
|
if ('me' === $item) {
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
if (!\array_key_exists('type', $item)) {
|
if (!\array_key_exists('type', $item)) {
|
||||||
throw new TransformationFailedException('the key "type" is missing on element');
|
throw new TransformationFailedException('the key "type" is missing on element');
|
||||||
}
|
}
|
||||||
@ -98,5 +101,6 @@ class EntityToJsonTransformer implements DataTransformerInterface
|
|||||||
'json',
|
'json',
|
||||||
$context,
|
$context,
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Form\Type;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Form\Type\DataTransformer\EntityToJsonTransformer;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick user dymically, using vuejs module "AddPerson".
|
||||||
|
*
|
||||||
|
* Possible options:
|
||||||
|
*
|
||||||
|
* - `multiple`: pick one or more users
|
||||||
|
* - `suggested`: a list of suggested users
|
||||||
|
* - `suggest_myself`: append the current user to the list of suggested
|
||||||
|
* - `as_id`: only the id will be set in the returned data
|
||||||
|
* - `submit_on_adding_new_entity`: the browser will immediately submit the form when new users are checked
|
||||||
|
*/
|
||||||
|
class PickUserOrMeDynamicType extends AbstractType
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly DenormalizerInterface $denormalizer,
|
||||||
|
private readonly SerializerInterface $serializer,
|
||||||
|
private readonly NormalizerInterface $normalizer,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->addViewTransformer(new EntityToJsonTransformer($this->denormalizer, $this->serializer, $options['multiple'], 'user'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
$view->vars['multiple'] = $options['multiple'];
|
||||||
|
$view->vars['types'] = ['user'];
|
||||||
|
$view->vars['uniqid'] = uniqid('pick_user_or_me_dyn');
|
||||||
|
$view->vars['suggested'] = [];
|
||||||
|
$view->vars['as_id'] = true === $options['as_id'] ? '1' : '0';
|
||||||
|
$view->vars['submit_on_adding_new_entity'] = true === $options['submit_on_adding_new_entity'] ? '1' : '0';
|
||||||
|
|
||||||
|
foreach ($options['suggested'] as $user) {
|
||||||
|
$view->vars['suggested'][] = $this->normalizer->normalize($user, 'json', ['groups' => 'read']);
|
||||||
|
}
|
||||||
|
// $user = /* should come from context */ $options['context'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefault('multiple', false)
|
||||||
|
->setAllowedTypes('multiple', ['bool'])
|
||||||
|
->setDefault('compound', false)
|
||||||
|
->setDefault('suggested', [])
|
||||||
|
// if set to true, only the id will be set inside the content. The denormalization will not work.
|
||||||
|
->setDefault('as_id', false)
|
||||||
|
->setAllowedTypes('as_id', ['bool'])
|
||||||
|
->setDefault('submit_on_adding_new_entity', false)
|
||||||
|
->setAllowedTypes('submit_on_adding_new_entity', ['bool']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'pick_entity_dynamic';
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,11 @@ function loadDynamicPicker(element) {
|
|||||||
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
|
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
|
||||||
|
|
||||||
apps.forEach(function (el) {
|
apps.forEach(function (el) {
|
||||||
|
let suggested;
|
||||||
|
let as_id;
|
||||||
|
let submit_on_adding_new_entity;
|
||||||
|
let label;
|
||||||
|
let isCurrentUserPicker;
|
||||||
const isMultiple = parseInt(el.dataset.multiple) === 1,
|
const isMultiple = parseInt(el.dataset.multiple) === 1,
|
||||||
uniqId = el.dataset.uniqid,
|
uniqId = el.dataset.uniqid,
|
||||||
input = element.querySelector(
|
input = element.querySelector(
|
||||||
@ -22,12 +27,13 @@ function loadDynamicPicker(element) {
|
|||||||
? JSON.parse(input.value)
|
? JSON.parse(input.value)
|
||||||
: input.value === "[]" || input.value === ""
|
: input.value === "[]" || input.value === ""
|
||||||
? null
|
? null
|
||||||
: [JSON.parse(input.value)],
|
: [JSON.parse(input.value)];
|
||||||
suggested = JSON.parse(el.dataset.suggested),
|
suggested = JSON.parse(el.dataset.suggested);
|
||||||
as_id = parseInt(el.dataset.asId) === 1,
|
as_id = parseInt(el.dataset.asId) === 1;
|
||||||
submit_on_adding_new_entity =
|
submit_on_adding_new_entity =
|
||||||
parseInt(el.dataset.submitOnAddingNewEntity) === 1,
|
parseInt(el.dataset.submitOnAddingNewEntity) === 1;
|
||||||
label = el.dataset.label;
|
label = el.dataset.label;
|
||||||
|
isCurrentUserPicker = uniqId.startsWith("pick_user_or_me_dyn");
|
||||||
|
|
||||||
if (!isMultiple) {
|
if (!isMultiple) {
|
||||||
if (input.value === "[]") {
|
if (input.value === "[]") {
|
||||||
@ -44,6 +50,7 @@ function loadDynamicPicker(element) {
|
|||||||
':uniqid="uniqid" ' +
|
':uniqid="uniqid" ' +
|
||||||
':suggested="notPickedSuggested" ' +
|
':suggested="notPickedSuggested" ' +
|
||||||
':label="label" ' +
|
':label="label" ' +
|
||||||
|
':isCurrentUserPicker="isCurrentUserPicker" ' +
|
||||||
'@addNewEntity="addNewEntity" ' +
|
'@addNewEntity="addNewEntity" ' +
|
||||||
'@removeEntity="removeEntity" ' +
|
'@removeEntity="removeEntity" ' +
|
||||||
'@addNewEntityProcessEnded="addNewEntityProcessEnded"' +
|
'@addNewEntityProcessEnded="addNewEntityProcessEnded"' +
|
||||||
@ -61,6 +68,7 @@ function loadDynamicPicker(element) {
|
|||||||
as_id,
|
as_id,
|
||||||
submit_on_adding_new_entity,
|
submit_on_adding_new_entity,
|
||||||
label,
|
label,
|
||||||
|
isCurrentUserPicker,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -89,7 +97,8 @@ function loadDynamicPicker(element) {
|
|||||||
const ids = this.picked.map((el) => el.id);
|
const ids = this.picked.map((el) => el.id);
|
||||||
input.value = ids.join(",");
|
input.value = ids.join(",");
|
||||||
}
|
}
|
||||||
console.log(entity);
|
console.log(this.picked);
|
||||||
|
// console.log(entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
|
@ -1,10 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul :class="listClasses" v-if="picked.length && displayPicked">
|
<ul :class="listClasses" v-if="picked.length && displayPicked">
|
||||||
<li v-for="p in picked" @click="removeEntity(p)" :key="p.type + p.id">
|
<li v-for="p in picked" @click="removeEntity(p)" :key="p.type + p.id">
|
||||||
<span class="chill_denomination">{{ p.text }}</span>
|
<span
|
||||||
|
v-if="'me' === p"
|
||||||
|
class="chill_denomination current-user updatedBy"
|
||||||
|
>{{ trans(USER_CURRENT_USER) }}</span
|
||||||
|
>
|
||||||
|
<span v-else class="chill_denomination">{{ p.text }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
|
<li v-if="isCurrentUserPicker" class="btn btn-sm btn-misc">
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
ref="itsMeCheckbox"
|
||||||
|
:type="multiple ? 'checkbox' : 'radio'"
|
||||||
|
@change="selectItsMe"
|
||||||
|
/>
|
||||||
|
{{ trans(USER_CURRENT_USER) }}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
<li class="add-persons">
|
<li class="add-persons">
|
||||||
<add-persons
|
<add-persons
|
||||||
:options="addPersonsOptions"
|
:options="addPersonsOptions"
|
||||||
@ -24,119 +39,83 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
import { ref, computed } from "vue";
|
||||||
|
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue"; // eslint-disable-line
|
||||||
import { appMessages } from "./i18n";
|
import { appMessages } from "./i18n";
|
||||||
|
import { trans, USER_CURRENT_USER } from "translator";
|
||||||
|
|
||||||
export default {
|
const props = defineProps({
|
||||||
name: "PickEntity",
|
multiple: Boolean,
|
||||||
props: {
|
types: Array,
|
||||||
multiple: {
|
picked: Array,
|
||||||
type: Boolean,
|
uniqid: String,
|
||||||
required: true,
|
removableIfSet: { type: Boolean, default: true },
|
||||||
},
|
displayPicked: { type: Boolean, default: true },
|
||||||
types: {
|
suggested: { type: Array, default: () => [] },
|
||||||
type: Array,
|
label: String,
|
||||||
required: true,
|
isCurrentUserPicker: { type: Boolean, default: false },
|
||||||
},
|
});
|
||||||
picked: {
|
|
||||||
required: true,
|
const emit = defineEmits([
|
||||||
},
|
"addNewEntity",
|
||||||
uniqid: {
|
"removeEntity",
|
||||||
type: String,
|
"addNewEntityProcessEnded",
|
||||||
required: true,
|
]);
|
||||||
},
|
|
||||||
removableIfSet: {
|
const itsMeCheckbox = ref(null);
|
||||||
type: Boolean,
|
const addPersons = ref(null);
|
||||||
default: true,
|
|
||||||
},
|
const addPersonsOptions = computed(() => ({
|
||||||
displayPicked: {
|
uniq: !props.multiple,
|
||||||
// display picked entities.
|
type: props.types,
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
suggested: {
|
|
||||||
type: Array,
|
|
||||||
default: [],
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ["addNewEntity", "removeEntity", "addNewEntityProcessEnded"],
|
|
||||||
components: {
|
|
||||||
AddPersons,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
key: "",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
addPersonsOptions() {
|
|
||||||
return {
|
|
||||||
uniq: !this.multiple,
|
|
||||||
type: this.types,
|
|
||||||
priority: null,
|
priority: null,
|
||||||
button: {
|
button: { size: "btn-sm", class: "btn-submit" },
|
||||||
size: "btn-sm",
|
}));
|
||||||
class: "btn-submit",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
translatedListOfTypes() {
|
|
||||||
if (this.label !== "") {
|
|
||||||
return this.label;
|
|
||||||
}
|
|
||||||
|
|
||||||
let trans = [];
|
const translatedListOfTypes = computed(() => {
|
||||||
this.types.forEach((t) => {
|
if (props.label) return props.label;
|
||||||
if (this.$props.multiple) {
|
let trans = props.types.map((t) =>
|
||||||
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
|
props.multiple
|
||||||
} else {
|
? appMessages.fr.pick_entity[t].toLowerCase()
|
||||||
trans.push(
|
: appMessages.fr.pick_entity[t + "_one"].toLowerCase(),
|
||||||
appMessages.fr.pick_entity[t + "_one"].toLowerCase(),
|
|
||||||
);
|
);
|
||||||
}
|
return props.multiple
|
||||||
});
|
? appMessages.fr.pick_entity.modal_title + trans.join(", ")
|
||||||
|
: appMessages.fr.pick_entity.modal_title_one + trans.join(", ");
|
||||||
|
});
|
||||||
|
|
||||||
if (this.$props.multiple) {
|
const listClasses = computed(() => ({
|
||||||
return (
|
|
||||||
appMessages.fr.pick_entity.modal_title + trans.join(", ")
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
appMessages.fr.pick_entity.modal_title_one +
|
|
||||||
trans.join(", ")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
listClasses() {
|
|
||||||
return {
|
|
||||||
"list-suggest": true,
|
"list-suggest": true,
|
||||||
"remove-items": this.$props.removableIfSet,
|
"remove-items": props.removableIfSet,
|
||||||
};
|
}));
|
||||||
},
|
|
||||||
},
|
const selectItsMe = (event) =>
|
||||||
methods: {
|
event.target.checked ? addNewSuggested("me") : removeEntity("me");
|
||||||
addNewSuggested(entity) {
|
|
||||||
this.$emit("addNewEntity", { entity: entity });
|
const addNewSuggested = (entity) => {
|
||||||
},
|
emit("addNewEntity", { entity });
|
||||||
addNewEntity({ selected, modal }) {
|
};
|
||||||
selected.forEach((item) => {
|
|
||||||
this.$emit("addNewEntity", { entity: item.result });
|
const addNewEntity = ({ selected, modal }) => {
|
||||||
}, this);
|
selected.forEach((item) => emit("addNewEntity", { entity: item.result }));
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
addPersons.value?.resetSearch();
|
||||||
modal.showModal = false;
|
modal.showModal = false;
|
||||||
this.$emit("addNewEntityProcessEnded");
|
emit("addNewEntityProcessEnded");
|
||||||
},
|
};
|
||||||
removeEntity(entity) {
|
|
||||||
if (!this.$props.removableIfSet) {
|
const removeEntity = (entity) => {
|
||||||
return;
|
if (!props.removableIfSet) return;
|
||||||
|
if (entity === "me" && itsMeCheckbox.value) {
|
||||||
|
itsMeCheckbox.value.checked = false;
|
||||||
}
|
}
|
||||||
this.$emit("removeEntity", { entity: entity });
|
emit("removeEntity", { entity });
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.current-user {
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
background-color: var(--bs-chill-l-gray) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -49,6 +49,7 @@ Name: Nom
|
|||||||
Label: Nom
|
Label: Nom
|
||||||
|
|
||||||
user:
|
user:
|
||||||
|
current_user: Utilisateur courant
|
||||||
profile:
|
profile:
|
||||||
title: Mon profil
|
title: Mon profil
|
||||||
Phonenumber successfully updated!: Numéro de téléphone mis à jour!
|
Phonenumber successfully updated!: Numéro de téléphone mis à jour!
|
||||||
|
@ -13,8 +13,8 @@ namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
|
|||||||
|
|
||||||
use Chill\MainBundle\Export\FilterInterface;
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
||||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
|
||||||
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
||||||
|
use Chill\MainBundle\Form\Type\PickUserOrMeDynamicType;
|
||||||
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||||
use Chill\PersonBundle\Export\Declarations;
|
use Chill\PersonBundle\Export\Declarations;
|
||||||
@ -24,6 +24,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
|||||||
final readonly class ReferrerFilter implements FilterInterface
|
final readonly class ReferrerFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
use \Chill\MainBundle\Export\ExportDataNormalizerTrait;
|
use \Chill\MainBundle\Export\ExportDataNormalizerTrait;
|
||||||
|
|
||||||
private const A = 'acp_referrer_filter_uhistory';
|
private const A = 'acp_referrer_filter_uhistory';
|
||||||
|
|
||||||
private const P = 'acp_referrer_filter_date';
|
private const P = 'acp_referrer_filter_date';
|
||||||
@ -68,7 +69,7 @@ final readonly class ReferrerFilter implements FilterInterface
|
|||||||
public function buildForm(FormBuilderInterface $builder): void
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('accepted_referrers', PickUserDynamicType::class, [
|
->add('accepted_referrers', PickUserOrMeDynamicType::class, [
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
])
|
])
|
||||||
->add('date_calc', PickRollingDateType::class, [
|
->add('date_calc', PickRollingDateType::class, [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user