mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'issue706_cc_in_workflow-2' into 'master'
Feature: [workflow] add users in cc Closes champs-libres/departement-de-la-vendee/chill#706 See merge request Chill-Projet/chill-bundles!517
This commit is contained in:
commit
48f5e7d21f
@ -93,6 +93,45 @@ class WorkflowApiController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of workflow which are waiting an action for the user.
|
||||||
|
*
|
||||||
|
* @Route("/api/1.0/main/workflow/my-cc", methods={"GET"})
|
||||||
|
*/
|
||||||
|
public function myWorkflowCc(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
if (!$this->security->isGranted('ROLE_USER') || !$this->security->getUser() instanceof User) {
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $this->entityWorkflowRepository->countByCc($this->security->getUser());
|
||||||
|
|
||||||
|
if ($request->query->getBoolean('countOnly', false)) {
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->serializer->serialize(new Counter($total), 'json'),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginator = $this->paginatorFactory->create($total);
|
||||||
|
|
||||||
|
$workflows = $this->entityWorkflowRepository->findByCc(
|
||||||
|
$this->security->getUser(),
|
||||||
|
['id' => 'DESC'],
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->serializer->serialize(new Collection($workflows, $paginator), 'json', ['groups' => ['read']]),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/api/1.0/main/workflow/{id}/subscribe", methods={"POST"})
|
* @Route("/api/1.0/main/workflow/{id}/subscribe", methods={"POST"})
|
||||||
*/
|
*/
|
||||||
|
@ -228,6 +228,33 @@ class WorkflowController extends AbstractController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/main/workflow/list/cc", name="chill_main_workflow_list_cc")
|
||||||
|
*/
|
||||||
|
public function myWorkflowsCc(Request $request): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
||||||
|
|
||||||
|
$total = $this->entityWorkflowRepository->countByDest($this->getUser());
|
||||||
|
$paginator = $this->paginatorFactory->create($total);
|
||||||
|
|
||||||
|
$workflows = $this->entityWorkflowRepository->findByCc(
|
||||||
|
$this->getUser(),
|
||||||
|
['createdAt' => 'DESC'],
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->render(
|
||||||
|
'@ChillMain/Workflow/list.html.twig',
|
||||||
|
[
|
||||||
|
'workflows' => $this->buildHandler($workflows),
|
||||||
|
'paginator' => $paginator,
|
||||||
|
'step' => 'cc',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/{_locale}/main/workflow/list/dest", name="chill_main_workflow_list_dest")
|
* @Route("/{_locale}/main/workflow/list/dest", name="chill_main_workflow_list_dest")
|
||||||
*/
|
*/
|
||||||
@ -306,7 +333,11 @@ class WorkflowController extends AbstractController
|
|||||||
$transitionForm = $this->createForm(
|
$transitionForm = $this->createForm(
|
||||||
WorkflowStepType::class,
|
WorkflowStepType::class,
|
||||||
$entityWorkflow->getCurrentStep(),
|
$entityWorkflow->getCurrentStep(),
|
||||||
['transition' => true, 'entity_workflow' => $entityWorkflow, 'suggested_users' => $usersInvolved]
|
[
|
||||||
|
'transition' => true,
|
||||||
|
'entity_workflow' => $entityWorkflow,
|
||||||
|
'suggested_users' => $usersInvolved
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$transitionForm->handleRequest($request);
|
$transitionForm->handleRequest($request);
|
||||||
@ -330,6 +361,7 @@ class WorkflowController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO symfony 5: add those "future" on context ($workflow->apply($entityWorkflow, $transition, $context)
|
// TODO symfony 5: add those "future" on context ($workflow->apply($entityWorkflow, $transition, $context)
|
||||||
|
$entityWorkflow->futureCcUsers = $transitionForm['future_cc_users']->getData();
|
||||||
$entityWorkflow->futureDestUsers = $transitionForm['future_dest_users']->getData();
|
$entityWorkflow->futureDestUsers = $transitionForm['future_dest_users']->getData();
|
||||||
$entityWorkflow->futureDestEmails = $transitionForm['future_dest_emails']->getData();
|
$entityWorkflow->futureDestEmails = $transitionForm['future_dest_emails']->getData();
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
|||||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Validator\Constraints\Entity\WorkflowStepUsersOnTransition;
|
||||||
use Chill\MainBundle\Workflow\Validator\EntityWorkflowCreation;
|
use Chill\MainBundle\Workflow\Validator\EntityWorkflowCreation;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
@ -24,6 +25,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
use Iterator;
|
use Iterator;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
use function count;
|
use function count;
|
||||||
use function is_array;
|
use function is_array;
|
||||||
|
|
||||||
@ -41,6 +43,13 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
|
|
||||||
use TrackUpdateTrait;
|
use TrackUpdateTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a list of future cc users for the next steps.
|
||||||
|
*
|
||||||
|
* @var array|User[]
|
||||||
|
*/
|
||||||
|
public array $futureCcUsers = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a list of future dest emails for the next steps.
|
* a list of future dest emails for the next steps.
|
||||||
*
|
*
|
||||||
@ -90,7 +99,7 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity=EntityWorkflowStep::class, mappedBy="entityWorkflow", orphanRemoval=true, cascade={"persist"})
|
* @ORM\OneToMany(targetEntity=EntityWorkflowStep::class, mappedBy="entityWorkflow", orphanRemoval=true, cascade={"persist"})
|
||||||
* @ORM\OrderBy({"transitionAt": "ASC", "id": "ASC"})
|
* @ORM\OrderBy({"transitionAt": "ASC", "id": "ASC"})
|
||||||
*
|
* @Assert\Valid(traverse=true)
|
||||||
* @var Collection|EntityWorkflowStep[]
|
* @var Collection|EntityWorkflowStep[]
|
||||||
*/
|
*/
|
||||||
private Collection $steps;
|
private Collection $steps;
|
||||||
|
@ -32,6 +32,12 @@ class EntityWorkflowStep
|
|||||||
*/
|
*/
|
||||||
private string $accessKey;
|
private string $accessKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToMany(targetEntity=User::class)
|
||||||
|
* @ORM\JoinTable(name="chill_main_workflow_entity_step_cc_user")
|
||||||
|
*/
|
||||||
|
private Collection $ccUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="text", options={"default": ""})
|
* @ORM\Column(type="text", options={"default": ""})
|
||||||
*/
|
*/
|
||||||
@ -114,11 +120,21 @@ class EntityWorkflowStep
|
|||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
$this->ccUser = new ArrayCollection();
|
||||||
$this->destUser = new ArrayCollection();
|
$this->destUser = new ArrayCollection();
|
||||||
$this->destUserByAccessKey = new ArrayCollection();
|
$this->destUserByAccessKey = new ArrayCollection();
|
||||||
$this->accessKey = bin2hex(openssl_random_pseudo_bytes(32));
|
$this->accessKey = bin2hex(openssl_random_pseudo_bytes(32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addCcUser(User $user): self
|
||||||
|
{
|
||||||
|
if (!$this->ccUser->contains($user)) {
|
||||||
|
$this->ccUser[] = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function addDestEmail(string $email): self
|
public function addDestEmail(string $email): self
|
||||||
{
|
{
|
||||||
if (!in_array($email, $this->destEmail, true)) {
|
if (!in_array($email, $this->destEmail, true)) {
|
||||||
@ -167,6 +183,11 @@ class EntityWorkflowStep
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCcUser(): Collection
|
||||||
|
{
|
||||||
|
return $this->ccUser;
|
||||||
|
}
|
||||||
|
|
||||||
public function getComment(): string
|
public function getComment(): string
|
||||||
{
|
{
|
||||||
return $this->comment;
|
return $this->comment;
|
||||||
@ -261,6 +282,13 @@ class EntityWorkflowStep
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function removeCcUser(User $user): self
|
||||||
|
{
|
||||||
|
$this->ccUser->removeElement($user);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function removeDestEmail(string $email): self
|
public function removeDestEmail(string $email): self
|
||||||
{
|
{
|
||||||
$this->destEmail = array_filter($this->destEmail, static function (string $existing) use ($email) {
|
$this->destEmail = array_filter($this->destEmail, static function (string $existing) use ($email) {
|
||||||
|
@ -156,6 +156,13 @@ class WorkflowStepType extends AbstractType
|
|||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'suggested' => $options['suggested_users'],
|
'suggested' => $options['suggested_users'],
|
||||||
])
|
])
|
||||||
|
->add('future_cc_users', PickUserDynamicType::class, [
|
||||||
|
'label' => 'workflow.cc for next steps',
|
||||||
|
'multiple' => true,
|
||||||
|
'mapped' => false,
|
||||||
|
'required' => false,
|
||||||
|
'suggested' => $options['suggested_users'],
|
||||||
|
])
|
||||||
->add('future_dest_emails', ChillCollectionType::class, [
|
->add('future_dest_emails', ChillCollectionType::class, [
|
||||||
'label' => 'workflow.dest by email',
|
'label' => 'workflow.dest by email',
|
||||||
'help' => 'workflow.dest by email help',
|
'help' => 'workflow.dest by email help',
|
||||||
@ -236,6 +243,20 @@ class WorkflowStepType extends AbstractType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
new Callback(
|
||||||
|
function ($step, ExecutionContextInterface $context, $payload) {
|
||||||
|
$form = $context->getObject();
|
||||||
|
|
||||||
|
foreach($form->get('future_dest_users')->getData() as $u) {
|
||||||
|
if (in_array($u, $form->get('future_cc_users')->getData(), true)) {
|
||||||
|
$context
|
||||||
|
->buildViolation('workflow.The user in cc cannot be a dest user in the same workflow step')
|
||||||
|
->atPath('ccUsers')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,8 @@ class NotificationTwigExtensionRuntime implements RuntimeExtensionInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $environment->render('@ChillMain/Notification/extension_list_notifications_for.html.twig', [
|
return $environment->render('@ChillMain/Notification/extension_list_notifications_for.html.twig', [
|
||||||
'notifications' => $notifications, 'appendCommentForms' => $appendCommentForms,
|
'notifications' => $notifications,
|
||||||
|
'appendCommentForms' => $appendCommentForms,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,13 @@ class EntityWorkflowRepository implements ObjectRepository
|
|||||||
$this->repository = $entityManager->getRepository(EntityWorkflow::class);
|
$this->repository = $entityManager->getRepository(EntityWorkflow::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countByCc(User $user): int
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByCc($user)->select('count(ew)');
|
||||||
|
|
||||||
|
return (int) $qb->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function countByDest(User $user): int
|
public function countByDest(User $user): int
|
||||||
{
|
{
|
||||||
$qb = $this->buildQueryByDest($user)->select('count(ew)');
|
$qb = $this->buildQueryByDest($user)->select('count(ew)');
|
||||||
@ -103,6 +110,19 @@ class EntityWorkflowRepository implements ObjectRepository
|
|||||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findByCc(User $user, ?array $orderBy = null, $limit = null, $offset = null): array
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByCc($user)->select('ew');
|
||||||
|
|
||||||
|
foreach ($orderBy as $key => $sort) {
|
||||||
|
$qb->addOrderBy('ew.' . $key, $sort);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->setMaxResults($limit)->setFirstResult($offset);
|
||||||
|
|
||||||
|
return $qb->getQuery()->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function findByDest(User $user, ?array $orderBy = null, $limit = null, $offset = null): array
|
public function findByDest(User $user, ?array $orderBy = null, $limit = null, $offset = null): array
|
||||||
{
|
{
|
||||||
$qb = $this->buildQueryByDest($user)->select('ew');
|
$qb = $this->buildQueryByDest($user)->select('ew');
|
||||||
@ -165,6 +185,25 @@ class EntityWorkflowRepository implements ObjectRepository
|
|||||||
return EntityWorkflow::class;
|
return EntityWorkflow::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildQueryByCc(User $user): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('ew');
|
||||||
|
|
||||||
|
$qb->join('ew.steps', 'step');
|
||||||
|
|
||||||
|
$qb->where(
|
||||||
|
$qb->expr()->andX(
|
||||||
|
$qb->expr()->isMemberOf(':user', 'step.ccUser'),
|
||||||
|
$qb->expr()->isNull('step.transitionAfter'),
|
||||||
|
$qb->expr()->eq('step.isFinal', "'FALSE'")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$qb->setParameter('user', $user);
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
private function buildQueryByDest(User $user): QueryBuilder
|
private function buildQueryByDest(User $user): QueryBuilder
|
||||||
{
|
{
|
||||||
$qb = $this->repository->createQueryBuilder('ew');
|
$qb = $this->repository->createQueryBuilder('ew');
|
||||||
|
@ -46,8 +46,7 @@
|
|||||||
:class="{'active': activeTab === 'MyTasks'}"
|
:class="{'active': activeTab === 'MyTasks'}"
|
||||||
@click="selectTab('MyTasks')">
|
@click="selectTab('MyTasks')">
|
||||||
{{ $t('my_tasks.tab') }}
|
{{ $t('my_tasks.tab') }}
|
||||||
<tab-counter :count="state.tasks.warning.count"></tab-counter>
|
<tab-counter :count="state.tasks.warning.count + state.tasks.alert.count"></tab-counter>
|
||||||
<tab-counter :count="state.tasks.alert.count"></tab-counter>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@ -55,7 +54,7 @@
|
|||||||
:class="{'active': activeTab === 'MyWorkflows'}"
|
:class="{'active': activeTab === 'MyWorkflows'}"
|
||||||
@click="selectTab('MyWorkflows')">
|
@click="selectTab('MyWorkflows')">
|
||||||
{{ $t('my_workflows.tab') }}
|
{{ $t('my_workflows.tab') }}
|
||||||
<tab-counter :count="state.workflows.count"></tab-counter>
|
<tab-counter :count="state.workflows.count + state.workflowsCc.count"></tab-counter>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item loading ms-auto py-2" v-if="loading">
|
<li class="nav-item loading ms-auto py-2" v-if="loading">
|
||||||
@ -150,4 +149,4 @@ export default {
|
|||||||
a.nav-link {
|
a.nav-link {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,88 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="alert alert-light">{{ $t('my_workflows.description') }}</div>
|
||||||
|
<my-workflows-table :workflows="workflows" />
|
||||||
|
|
||||||
<div class="alert alert-light">{{ $t('my_workflows.description') }}</div>
|
<div class="alert alert-light">{{ $t('my_workflows.description_cc') }}</div>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
<my-workflows-table :workflows="workflowsCc" />
|
||||||
<tab-table v-else>
|
|
||||||
<template v-slot:thead>
|
|
||||||
<th scope="col">{{ $t('Object_workflow') }}</th>
|
|
||||||
<th scope="col">{{ $t('Step') }}</th>
|
|
||||||
<th scope="col">{{ $t('concerned_users') }}</th>
|
|
||||||
<th scope="col"></th>
|
|
||||||
</template>
|
|
||||||
<template v-slot:tbody>
|
|
||||||
<tr v-for="(w, i) in workflows.results" :key="`workflow-${i}`">
|
|
||||||
<td>{{ w.title }}</td>
|
|
||||||
<td>
|
|
||||||
<div class="workflow">
|
|
||||||
<div class="breadcrumb">
|
|
||||||
<i class="fa fa-circle me-1 text-chill-yellow mx-2"></i>
|
|
||||||
<span class="mx-2">{{ getStep(w) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td v-if="w.datas.persons !== null">
|
|
||||||
<span v-for="p in w.datas.persons" class="me-1" :key="p.id">
|
|
||||||
<on-the-fly
|
|
||||||
:type="p.type"
|
|
||||||
:id="p.id"
|
|
||||||
:buttonText="p.textAge"
|
|
||||||
:displayBadge="'true' === 'true'"
|
|
||||||
action="show">
|
|
||||||
</on-the-fly>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a class="btn btn-sm btn-show" :href="getUrl(w)">
|
|
||||||
{{ $t('show_entity', { entity: $t('the_workflow') }) }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
|
||||||
</tab-table>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from "vuex";
|
import { mapState } from "vuex";
|
||||||
import TabTable from "./TabTable";
|
import MyWorkflowsTable from './MyWorkflowsTable.vue';
|
||||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MyWorkflows",
|
name: "MyWorkflows",
|
||||||
components: {
|
components: {
|
||||||
TabTable,
|
MyWorkflowsTable
|
||||||
OnTheFly
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState([
|
||||||
'workflows',
|
'workflows',
|
||||||
|
'workflowsCc',
|
||||||
]),
|
]),
|
||||||
...mapGetters([
|
|
||||||
'isWorkflowsLoaded',
|
|
||||||
]),
|
|
||||||
noResults() {
|
|
||||||
if (!this.isWorkflowsLoaded) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return this.workflows.count === 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getUrl(w) {
|
|
||||||
return `/fr/main/workflow/${w.id}/show`;
|
|
||||||
},
|
|
||||||
getStep(w) {
|
|
||||||
const lastStep = w.steps.length - 1
|
|
||||||
return w.steps[lastStep].currentStep.text;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
span.outdated {
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--bs-warning);
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="hasNoResults(workflows)" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">{{ $t('Object_workflow') }}</th>
|
||||||
|
<th scope="col">{{ $t('Step') }}</th>
|
||||||
|
<th scope="col">{{ $t('concerned_users') }}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(w, i) in workflows.results" :key="`workflow-${i}`">
|
||||||
|
<td>{{ w.title }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="workflow">
|
||||||
|
<div class="breadcrumb">
|
||||||
|
<i class="fa fa-circle me-1 text-chill-yellow mx-2"></i>
|
||||||
|
<span class="mx-2">{{ getStep(w) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td v-if="w.datas.persons !== null">
|
||||||
|
<span v-for="p in w.datas.persons" class="me-1" :key="p.id">
|
||||||
|
<on-the-fly
|
||||||
|
:type="p.type"
|
||||||
|
:id="p.id"
|
||||||
|
:buttonText="p.textAge"
|
||||||
|
:displayBadge="'true' === 'true'"
|
||||||
|
action="show">
|
||||||
|
</on-the-fly>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-show" :href="getUrl(w)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_workflow') }) }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from "vuex";
|
||||||
|
import TabTable from "./TabTable";
|
||||||
|
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyWorkflows",
|
||||||
|
components: {
|
||||||
|
TabTable,
|
||||||
|
OnTheFly
|
||||||
|
},
|
||||||
|
props: ['workflows'],
|
||||||
|
computed: {
|
||||||
|
...mapGetters([
|
||||||
|
'isWorkflowsLoaded',
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
hasNoResults(workflows) {
|
||||||
|
if (!this.isWorkflowsLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return workflows.count === 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getUrl(w) {
|
||||||
|
return `/fr/main/workflow/${w.id}/show`;
|
||||||
|
},
|
||||||
|
getStep(w) {
|
||||||
|
const lastStep = w.steps.length - 1
|
||||||
|
return w.steps[lastStep].currentStep.text;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
span.outdated {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--bs-warning);
|
||||||
|
}
|
||||||
|
</style>
|
@ -24,7 +24,8 @@ const appMessages = {
|
|||||||
},
|
},
|
||||||
my_workflows: {
|
my_workflows: {
|
||||||
tab: "Mes workflows",
|
tab: "Mes workflows",
|
||||||
description: "Liste des workflows en attente d'une action."
|
description: "Liste des workflows en attente d'une action.",
|
||||||
|
description_cc: "Liste des workflows dont je suis en copie."
|
||||||
},
|
},
|
||||||
opening_date: "Date d'ouverture",
|
opening_date: "Date d'ouverture",
|
||||||
social_issues: "Problématiques sociales",
|
social_issues: "Problématiques sociales",
|
||||||
|
@ -22,6 +22,7 @@ const store = createStore({
|
|||||||
accompanyingCourses: {},
|
accompanyingCourses: {},
|
||||||
notifications: {},
|
notifications: {},
|
||||||
workflows: {},
|
workflows: {},
|
||||||
|
workflowsCc: {},
|
||||||
errorMsg: [],
|
errorMsg: [],
|
||||||
loading: false
|
loading: false
|
||||||
},
|
},
|
||||||
@ -87,6 +88,9 @@ const store = createStore({
|
|||||||
addWorkflows(state, workflows) {
|
addWorkflows(state, workflows) {
|
||||||
state.workflows = workflows;
|
state.workflows = workflows;
|
||||||
},
|
},
|
||||||
|
addWorkflowsCc(state, workflows) {
|
||||||
|
state.workflowsCc = workflows;
|
||||||
|
},
|
||||||
setLoading(state, bool) {
|
setLoading(state, bool) {
|
||||||
state.loading = bool;
|
state.loading = bool;
|
||||||
},
|
},
|
||||||
@ -195,17 +199,23 @@ const store = createStore({
|
|||||||
case 'MyWorkflows':
|
case 'MyWorkflows':
|
||||||
if (!getters.isWorflowsLoaded) {
|
if (!getters.isWorflowsLoaded) {
|
||||||
commit('setLoading', true);
|
commit('setLoading', true);
|
||||||
const url = '/api/1.0/main/workflow/my';
|
makeFetch('GET', '/api/1.0/main/workflow/my')
|
||||||
makeFetch('GET', url)
|
.then((response) => {
|
||||||
.then((response) => {
|
commit('addWorkflows', response);
|
||||||
console.log('workflows', response)
|
makeFetch('GET', '/api/1.0/main/workflow/my-cc')
|
||||||
commit('addWorkflows', response);
|
.then((response) => {
|
||||||
commit('setLoading', false);
|
commit('addWorkflowsCc', response);
|
||||||
})
|
commit('setLoading', false);
|
||||||
.catch((error) => {
|
})
|
||||||
commit('catchError', error);
|
.catch((error) => {
|
||||||
throw error;
|
commit('catchError', error);
|
||||||
});
|
throw error;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -30,11 +30,27 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if c.notification.addressees|length > 0 %}
|
{% if c.notification.addressees|length > 0 %}
|
||||||
<li class="notification-to">
|
<li class="notification-to">
|
||||||
<span class="item-key">
|
{% if c.notification_cc is defined %}
|
||||||
|
{% if c.notification_cc %}
|
||||||
|
<span class="item-key">
|
||||||
|
<abbr title="{{ 'notification.sent_cc'|trans }}">
|
||||||
|
{{ 'notification.cc'|trans }} :
|
||||||
|
</abbr>
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="item-key">
|
||||||
|
<abbr title="{{ 'notification.sent_to'|trans }}">
|
||||||
|
{{ 'notification.to'|trans }} :
|
||||||
|
</abbr>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="item-key">
|
||||||
<abbr title="{{ 'notification.sent_to'|trans }}">
|
<abbr title="{{ 'notification.sent_to'|trans }}">
|
||||||
{{ 'notification.to'|trans }} :
|
{{ 'notification.to'|trans }} :
|
||||||
</abbr>
|
</abbr>
|
||||||
</span>
|
</span>
|
||||||
|
{% endif %}
|
||||||
{% for a in c.notification.addressees %}
|
{% for a in c.notification.addressees %}
|
||||||
<span class="badge-user">
|
<span class="badge-user">
|
||||||
{{ a|chill_entity_render_string }}
|
{{ a|chill_entity_render_string }}
|
||||||
|
@ -50,7 +50,8 @@
|
|||||||
{% for data in datas %}
|
{% for data in datas %}
|
||||||
{% set notification = data.notification %}
|
{% set notification = data.notification %}
|
||||||
{% include 'ChillMainBundle:Notification:_list_item.html.twig' with {
|
{% include 'ChillMainBundle:Notification:_list_item.html.twig' with {
|
||||||
'fold_item': true
|
'fold_item': true,
|
||||||
|
'notification_cc': data.template_data.notificationCc is defined ? data.template_data.notificationCc : false
|
||||||
} %}
|
} %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +27,8 @@
|
|||||||
},
|
},
|
||||||
'action_button': false,
|
'action_button': false,
|
||||||
'full_content': true,
|
'full_content': true,
|
||||||
'fold_item': false
|
'fold_item': false,
|
||||||
|
'notification_cc': handler.getTemplateData(notification).notificationCc is defined ? handler.getTemplateData(notification).notificationCc : false
|
||||||
} %}
|
} %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@
|
|||||||
<div id="futureDests">
|
<div id="futureDests">
|
||||||
{{ form_row(transition_form.future_dest_users) }}
|
{{ form_row(transition_form.future_dest_users) }}
|
||||||
|
|
||||||
|
{{ form_row(transition_form.future_cc_users) }}
|
||||||
|
|
||||||
{{ form_row(transition_form.future_dest_emails) }}
|
{{ form_row(transition_form.future_dest_emails) }}
|
||||||
{{ form_errors(transition_form.future_dest_users) }}
|
{{ form_errors(transition_form.future_dest_users) }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,6 +81,15 @@
|
|||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step.ccUser|length > 0 %}
|
||||||
|
<p><b>{{ 'workflow.Users put in Cc'|trans }} : </b></p>
|
||||||
|
<ul>
|
||||||
|
{% for u in step.ccUser %}
|
||||||
|
<li>{{ u|chill_entity_render_box }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if entity_workflow.currentStep.destEmail|length > 0 %}
|
{% if entity_workflow.currentStep.destEmail|length > 0 %}
|
||||||
<p><b>{{ 'workflow.An access key was also sent to those addresses'|trans }} :</b></p>
|
<p><b>{{ 'workflow.An access key was also sent to those addresses'|trans }} :</b></p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-10 workflow">
|
<div class="col-12 workflow">
|
||||||
|
|
||||||
<h1 class="mb-5">{{ block('title') }}</h1>
|
<h1 class="mb-5">{{ block('title') }}</h1>
|
||||||
|
|
||||||
@ -25,6 +25,12 @@
|
|||||||
{{ 'workflow.dest'|trans }}
|
{{ 'workflow.dest'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{{ path('chill_main_workflow_list_cc') }}"
|
||||||
|
class="nav-link {% if step == 'cc' %}active{% endif %}">
|
||||||
|
{{ 'workflow.cc'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{ path('chill_main_workflow_list_previous_without_reaction') }}"
|
<a href="{{ path('chill_main_workflow_list_previous_without_reaction') }}"
|
||||||
class="nav-link {% if step == 'previous_without_reaction' %}active{% endif %}">
|
class="nav-link {% if step == 'previous_without_reaction' %}active{% endif %}">
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
{% for d in step.destUser %}{{ d|chill_entity_render_string }}{% if not loop.last %}, {% endif %}{% endfor %}
|
{% for d in step.destUser %}{{ d|chill_entity_render_string }}{% if not loop.last %}, {% endif %}{% endfor %}
|
||||||
</b>
|
</b>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="item-key">{{ 'workflow.Cc'|trans ~ ' : ' }}</span>
|
||||||
|
<b>
|
||||||
|
{% for u in step.ccUser %}{{ u|chill_entity_render_string }}{% if not loop.last %}, {% endif %}{% endfor %}
|
||||||
|
</b>
|
||||||
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>
|
<li>
|
||||||
<span class="item-key">{{ 'workflow.Created by'|trans ~ ' : ' }}</span>
|
<span class="item-key">{{ 'workflow.Created by'|trans ~ ' : ' }}</span>
|
||||||
|
@ -50,6 +50,10 @@ class EntityWorkflowTransitionEventSubscriber implements EventSubscriberInterfac
|
|||||||
/** @var EntityWorkflow $entityWorkflow */
|
/** @var EntityWorkflow $entityWorkflow */
|
||||||
$entityWorkflow = $event->getSubject();
|
$entityWorkflow = $event->getSubject();
|
||||||
|
|
||||||
|
foreach ($entityWorkflow->futureCcUsers as $user) {
|
||||||
|
$entityWorkflow->getCurrentStep()->addCcUser($user);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($entityWorkflow->futureDestUsers as $user) {
|
foreach ($entityWorkflow->futureDestUsers as $user) {
|
||||||
$entityWorkflow->getCurrentStep()->addDestUser($user);
|
$entityWorkflow->getCurrentStep()->addDestUser($user);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,9 @@ class NotificationOnTransition implements EventSubscriberInterface
|
|||||||
// the subscriber to final, only if final
|
// the subscriber to final, only if final
|
||||||
$entityWorkflow->isFinal() ? $entityWorkflow->getSubscriberToFinal()->toArray() : [],
|
$entityWorkflow->isFinal() ? $entityWorkflow->getSubscriberToFinal()->toArray() : [],
|
||||||
// the dests for the current step
|
// the dests for the current step
|
||||||
$entityWorkflow->getCurrentStep()->getDestUser()->toArray()
|
$entityWorkflow->getCurrentStep()->getDestUser()->toArray(),
|
||||||
|
// the cc users for the current step
|
||||||
|
$entityWorkflow->getCurrentStep()->getCcUser()->toArray()
|
||||||
) as $dest) {
|
) as $dest) {
|
||||||
$dests[spl_object_hash($dest)] = $dest;
|
$dests[spl_object_hash($dest)] = $dest;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
|||||||
use Chill\MainBundle\Notification\NotificationHandlerInterface;
|
use Chill\MainBundle\Notification\NotificationHandlerInterface;
|
||||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
|
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
|
||||||
use Chill\MainBundle\Workflow\EntityWorkflowManager;
|
use Chill\MainBundle\Workflow\EntityWorkflowManager;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
class WorkflowNotificationHandler implements NotificationHandlerInterface
|
class WorkflowNotificationHandler implements NotificationHandlerInterface
|
||||||
{
|
{
|
||||||
@ -23,10 +24,16 @@ class WorkflowNotificationHandler implements NotificationHandlerInterface
|
|||||||
|
|
||||||
private EntityWorkflowRepository $entityWorkflowRepository;
|
private EntityWorkflowRepository $entityWorkflowRepository;
|
||||||
|
|
||||||
public function __construct(EntityWorkflowRepository $entityWorkflowRepository, EntityWorkflowManager $entityWorkflowManager)
|
private Security $security;
|
||||||
{
|
|
||||||
|
public function __construct(
|
||||||
|
EntityWorkflowRepository $entityWorkflowRepository,
|
||||||
|
EntityWorkflowManager $entityWorkflowManager,
|
||||||
|
Security $security
|
||||||
|
) {
|
||||||
$this->entityWorkflowRepository = $entityWorkflowRepository;
|
$this->entityWorkflowRepository = $entityWorkflowRepository;
|
||||||
$this->entityWorkflowManager = $entityWorkflowManager;
|
$this->entityWorkflowManager = $entityWorkflowManager;
|
||||||
|
$this->security = $security;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTemplate(Notification $notification, array $options = []): string
|
public function getTemplate(Notification $notification, array $options = []): string
|
||||||
@ -37,13 +44,28 @@ class WorkflowNotificationHandler implements NotificationHandlerInterface
|
|||||||
public function getTemplateData(Notification $notification, array $options = []): array
|
public function getTemplateData(Notification $notification, array $options = []): array
|
||||||
{
|
{
|
||||||
$entityWorkflow = $this->entityWorkflowRepository->find($notification->getRelatedEntityId());
|
$entityWorkflow = $this->entityWorkflowRepository->find($notification->getRelatedEntityId());
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'entity_workflow' => $entityWorkflow,
|
'entity_workflow' => $entityWorkflow,
|
||||||
'handler' => $this->entityWorkflowManager->getHandler($entityWorkflow),
|
'handler' => $this->entityWorkflowManager->getHandler($entityWorkflow),
|
||||||
|
'notificationCc' => $this->isNotificationCc($notification),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function isNotificationCc(Notification $notification): bool
|
||||||
|
{
|
||||||
|
$notificationCc = false;
|
||||||
|
|
||||||
|
if ($notification->getRelatedEntityClass() === EntityWorkflow::class) {
|
||||||
|
$relatedEntity = $this->entityWorkflowRepository->findOneBy(['id' => $notification->getRelatedEntityId()]);
|
||||||
|
|
||||||
|
if ($relatedEntity->getCurrentStepCreatedBy() !== $this->security->getUser()) {
|
||||||
|
$notificationCc = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $notificationCc;
|
||||||
|
}
|
||||||
|
|
||||||
public function supports(Notification $notification, array $options = []): bool
|
public function supports(Notification $notification, array $options = []): bool
|
||||||
{
|
{
|
||||||
return $notification->getRelatedEntityClass() === EntityWorkflow::class;
|
return $notification->getRelatedEntityClass() === EntityWorkflow::class;
|
||||||
|
@ -826,4 +826,20 @@ paths:
|
|||||||
$ref: '#/components/schemas/Workflow'
|
$ref: '#/components/schemas/Workflow'
|
||||||
403:
|
403:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
/1.0/main/workflow/my-cc:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- workflow
|
||||||
|
summary: Return a list of workflows for which user was notified in Cc
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Workflow'
|
||||||
|
403:
|
||||||
|
description: "Unauthorized"
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
<?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\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20230321134155 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user DROP CONSTRAINT FK_9FC79037E6AF9D4');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user DROP CONSTRAINT FK_9FC7903A76ED395');
|
||||||
|
$this->addSql('DROP TABLE chill_main_workflow_entity_step_cc_user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add cc User to workflow step';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('CREATE TABLE chill_main_workflow_entity_step_cc_user (entityworkflowstep_id INT NOT NULL, user_id INT NOT NULL, PRIMARY KEY(entityworkflowstep_id, user_id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_9FC79037E6AF9D4 ON chill_main_workflow_entity_step_cc_user (entityworkflowstep_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_9FC7903A76ED395 ON chill_main_workflow_entity_step_cc_user (user_id)');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user ADD CONSTRAINT FK_9FC79037E6AF9D4 FOREIGN KEY (entityworkflowstep_id) REFERENCES chill_main_workflow_entity_step (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user ADD CONSTRAINT FK_9FC7903A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
}
|
@ -447,6 +447,7 @@ workflow:
|
|||||||
Created by: Créé par
|
Created by: Créé par
|
||||||
My decision: Ma décision
|
My decision: Ma décision
|
||||||
Next step: Prochaine étape
|
Next step: Prochaine étape
|
||||||
|
cc for next steps: Utilisateurs en copie
|
||||||
dest for next steps: Utilisateurs qui valideront la prochaine étape
|
dest for next steps: Utilisateurs qui valideront la prochaine étape
|
||||||
Freeze: Geler
|
Freeze: Geler
|
||||||
Freezed: Gelé
|
Freezed: Gelé
|
||||||
@ -465,12 +466,14 @@ workflow:
|
|||||||
Document (n°%doc%): "Document (n°%doc%)"
|
Document (n°%doc%): "Document (n°%doc%)"
|
||||||
Work (n°%w%): "Action d'accompagnement (n°%w%)"
|
Work (n°%w%): "Action d'accompagnement (n°%w%)"
|
||||||
subscribed: Workflows suivis
|
subscribed: Workflows suivis
|
||||||
|
cc: Workflows dont je suis en copie
|
||||||
dest: Workflows en attente d'action
|
dest: Workflows en attente d'action
|
||||||
you subscribed to all steps: Vous recevrez une notification à chaque étape
|
you subscribed to all steps: Vous recevrez une notification à chaque étape
|
||||||
you subscribed to final step: Vous recevrez une notification à l'étape finale
|
you subscribed to final step: Vous recevrez une notification à l'étape finale
|
||||||
Current step: Étape actuelle
|
Current step: Étape actuelle
|
||||||
Comment on last change: Commentaire à la transition précédente
|
Comment on last change: Commentaire à la transition précédente
|
||||||
Users allowed to apply transition: Utilisateurs pouvant valider cette étape
|
Users allowed to apply transition: Utilisateurs pouvant valider cette étape
|
||||||
|
Users put in Cc: Utilisateurs mis en copie
|
||||||
Workflow deleted with success: Le workflow a été supprimé
|
Workflow deleted with success: Le workflow a été supprimé
|
||||||
Delete workflow ?: Supprimer le workflow ?
|
Delete workflow ?: Supprimer le workflow ?
|
||||||
Are you sure you want to delete this workflow ?: Êtes-vous sûr·e de vouloir supprimer ce workflow ?
|
Are you sure you want to delete this workflow ?: Êtes-vous sûr·e de vouloir supprimer ce workflow ?
|
||||||
@ -487,6 +490,7 @@ workflow:
|
|||||||
Previous transitionned: Anciens workflows
|
Previous transitionned: Anciens workflows
|
||||||
Previous workflow transitionned help: Workflows où vous avez exécuté une action.
|
Previous workflow transitionned help: Workflows où vous avez exécuté une action.
|
||||||
For: Pour
|
For: Pour
|
||||||
|
Cc: Cc
|
||||||
You must select a next step, pick another decision if no next steps are available: Il faut une prochaine étape. Choissisez une autre décision si nécessaire.
|
You must select a next step, pick another decision if no next steps are available: Il faut une prochaine étape. Choissisez une autre décision si nécessaire.
|
||||||
An access key was also sent to those addresses: Un lien d'accès a été envoyé à ces adresses
|
An access key was also sent to those addresses: Un lien d'accès a été envoyé à ces adresses
|
||||||
Those users are also granted to apply a transition by using an access key: Ces utilisateurs ont obtenu l'accès grâce au lien reçu par email
|
Those users are also granted to apply a transition by using an access key: Ces utilisateurs ont obtenu l'accès grâce au lien reçu par email
|
||||||
@ -521,7 +525,9 @@ notification:
|
|||||||
list: Notifications
|
list: Notifications
|
||||||
Sent: Envoyé
|
Sent: Envoyé
|
||||||
to: À
|
to: À
|
||||||
|
cc: Cc
|
||||||
sent_to: Destinataire(s)
|
sent_to: Destinataire(s)
|
||||||
|
sent_cc: En copie
|
||||||
from: De
|
from: De
|
||||||
received_from: Expéditeur
|
received_from: Expéditeur
|
||||||
you were notified by %sender%: Vous avez été notifié par %sender%
|
you were notified by %sender%: Vous avez été notifié par %sender%
|
||||||
|
@ -373,6 +373,7 @@ workflow:
|
|||||||
Created by: Créé par
|
Created by: Créé par
|
||||||
My decision: Ma décision
|
My decision: Ma décision
|
||||||
Next step: Prochaine étape
|
Next step: Prochaine étape
|
||||||
|
cc for next steps: Utilisateurs en copie
|
||||||
dest for next steps: Utilisateurs qui valideront la prochaine étape
|
dest for next steps: Utilisateurs qui valideront la prochaine étape
|
||||||
Freeze: Geler
|
Freeze: Geler
|
||||||
Freezed: Gelé
|
Freezed: Gelé
|
||||||
@ -392,11 +393,13 @@ workflow:
|
|||||||
Work (n°%w%): "Action d'accompagnement (n°%w%)"
|
Work (n°%w%): "Action d'accompagnement (n°%w%)"
|
||||||
subscribed: Workflows suivis
|
subscribed: Workflows suivis
|
||||||
dest: Workflows en attente d'action
|
dest: Workflows en attente d'action
|
||||||
|
cc: Workflows dont je suis en copie
|
||||||
you subscribed to all steps: Vous recevrez une notification à chaque étape
|
you subscribed to all steps: Vous recevrez une notification à chaque étape
|
||||||
you subscribed to final step: Vous recevrez une notification à l'étape finale
|
you subscribed to final step: Vous recevrez une notification à l'étape finale
|
||||||
Current step: Étape actuelle
|
Current step: Étape actuelle
|
||||||
Comment on last change: Commentaire à la transition précédente
|
Comment on last change: Commentaire à la transition précédente
|
||||||
Users allowed to apply transition: Utilisateurs pouvant valider cette étape
|
Users allowed to apply transition: Utilisateurs pouvant valider cette étape
|
||||||
|
Users put in Cc: Utilisateurs mis en copie
|
||||||
Workflow deleted with success: Le workflow a été supprimé
|
Workflow deleted with success: Le workflow a été supprimé
|
||||||
Delete workflow ?: Supprimer le workflow ?
|
Delete workflow ?: Supprimer le workflow ?
|
||||||
Are you sure you want to delete this workflow ?: Êtes-vous sûr·e de vouloir supprimer ce workflow ?
|
Are you sure you want to delete this workflow ?: Êtes-vous sûr·e de vouloir supprimer ce workflow ?
|
||||||
@ -414,6 +417,7 @@ workflow:
|
|||||||
Previous transitionned: Anciens workflows
|
Previous transitionned: Anciens workflows
|
||||||
Previous workflow transitionned help: Workflows où vous avez exécuté une action.
|
Previous workflow transitionned help: Workflows où vous avez exécuté une action.
|
||||||
For: Pour
|
For: Pour
|
||||||
|
Cc: Cc
|
||||||
|
|
||||||
|
|
||||||
Subscribe final: Recevoir une notification à l'étape finale
|
Subscribe final: Recevoir une notification à l'étape finale
|
||||||
@ -442,7 +446,9 @@ notification:
|
|||||||
list: Notifications
|
list: Notifications
|
||||||
Sent: Envoyé
|
Sent: Envoyé
|
||||||
to: À
|
to: À
|
||||||
|
cc: Cc
|
||||||
sent_to: Destinataire(s)
|
sent_to: Destinataire(s)
|
||||||
|
sent_cc: En copie
|
||||||
from: De
|
from: De
|
||||||
received_from: Expéditeur
|
received_from: Expéditeur
|
||||||
you were notified by %sender%: Vous avez été notifié par %sender%
|
you were notified by %sender%: Vous avez été notifié par %sender%
|
||||||
|
@ -11,6 +11,8 @@ A permission is already present for the same role and scope: Une permission est
|
|||||||
#UserCircleConsistency
|
#UserCircleConsistency
|
||||||
"{{ username }} is not allowed to see entities published in this circle": "{{ username }} n'est pas autorisé à voir l'élément publié dans ce cercle."
|
"{{ username }} is not allowed to see entities published in this circle": "{{ username }} n'est pas autorisé à voir l'élément publié dans ce cercle."
|
||||||
|
|
||||||
|
The user in cc cannot be a dest user in the same workflow step: Un utilisateur en Cc ne peut pas être un utilisateur qui valide.
|
||||||
|
|
||||||
#password request
|
#password request
|
||||||
This username or email does not exists: Cet utilisateur ou email n'est pas présent dans la base de donnée
|
This username or email does not exists: Cet utilisateur ou email n'est pas présent dans la base de donnée
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ notification:
|
|||||||
|
|
||||||
workflow:
|
workflow:
|
||||||
You must add at least one dest user or email: Indiquez au moins un destinataire ou une adresse email
|
You must add at least one dest user or email: Indiquez au moins un destinataire ou une adresse email
|
||||||
|
The user in cc cannot be a dest user in the same workflow step: L'utilisateur en copie ne peut pas être présent dans les utilisateurs qui valideront la prochaine étape
|
||||||
|
|
||||||
rolling_date:
|
rolling_date:
|
||||||
When fixed date is selected, you must provide a date: Indiquez la date fixe choisie
|
When fixed date is selected, you must provide a date: Indiquez la date fixe choisie
|
||||||
|
Loading…
x
Reference in New Issue
Block a user