105 worflow

This commit is contained in:
2022-01-24 13:17:46 +00:00
committed by Julien Fastré
parent daff4e4200
commit c7dbaae8d6
110 changed files with 5176 additions and 392 deletions

View File

@@ -1,5 +1,5 @@
// Access to Bootstrap variables and mixins
@import '~ChillMainAssets/module/bootstrap/shared';
@import 'ChillMainAssets/module/bootstrap/shared';
// Chill variables
@import './scss/chill_variables';
@@ -277,11 +277,17 @@ table.table-bordered {
}
}
/// meta-data
div.updatedBy,
div.metadata {
span.user, span.date {
text-decoration: underline dotted;
}
}
div.metadata {
font-size: smaller;
color: $gray-600;
span.user, span.date {
text-decoration: underline dotted;
&:hover {
color: $gray-700;
}
@@ -424,7 +430,63 @@ span.item-key {
//text-decoration: dotted underline;
}
/// Workflows
div.workflow {
section.step {
border: 1px solid $chill-l-gray;
padding: 1em 2em;
div.flex-table {
margin: 1.5em -2em;
}
}
div.to-decision,
div.decided {
font-variant: all-small-caps;
margin-left: 1em;
}
div.to-decision {
font-weight: 300;
}
div.decided {
font-weight: 600;
}
div.breadcrumb {
display: initial;
margin-bottom: 0;
padding-right: 0.5em;
background-color: tint-color($chill-yellow, 90%);
border: 1px solid $chill-yellow;
color: $primary;
border-radius: 1.5em;
font-size: 12pt;
font-weight: 500;
font-variant: small-caps;
span, a {
cursor: pointer;
text-decoration: none;
&:hover {
font-weight: 700;
}
}
}
}
// Override bootstrap popover styles
div.popover {
box-shadow: 0 0 10px -5px $dark;
.popover-arrow {}
.popover-header {}
.popover-body {}
// Specific worflow breadcrumb popover
&.workflow-transition {
.popover-header {
font-variant: small-caps;
}
}
}
// increase toast message z-index (above all modals)
div.v-toast {
z-index: 10000!important;
}
}

View File

@@ -18,6 +18,7 @@ $chill-theme-buttons: (
"show": $chill-blue,
"view": $chill-blue,
"misc": $gray-300,
"download": $gray-300,
"cancel": $gray-300,
"choose": $gray-300,
"notify": $gray-300,
@@ -78,6 +79,7 @@ $chill-theme-buttons: (
&.btn-choose::before,
&.btn-notify::before,
&.btn-tpchild::before,
&.btn-download::before,
&.btn-cancel::before {
font: normal normal normal 14px/1 ForkAwesome;
margin-right: 0.5em;
@@ -105,6 +107,7 @@ $chill-theme-buttons: (
&.btn-unlink::before { content: "\f127"; } // fa-chain-broken
&.btn-notify::before { content: "\f1d8"; } // fa-paper-plane
&.btn-tpchild::before { content: "\f007"; } // fa-user
&.btn-download::before { content: "\f019"; } // fa-download
}

View File

@@ -41,6 +41,15 @@ div.flex-table {
margin-right: 5px;
}
}
div.item-meta {
flex-grow: 1 !important;
flex-shrink: 1 !important;
width: unset !important;
display: flex;
flex-direction: column;
justify-content: center;
}
}
/*

View File

@@ -68,6 +68,7 @@ div.notification-show {
}
// Override bootstrap accordion
div#workflow-fold,
div#notification-fold {
.accordion-button {
padding: 0;
@@ -78,3 +79,14 @@ div#notification-fold {
}
}
}
// Counter
div.notification-counter {
span {
&:not(:first-child) {
&::before {
content: '/ ';
}
}
}
}

View File

@@ -106,6 +106,8 @@ section.chill-entity {
// used for comment-embeddable
&.entity-comment-embeddable {
width: 100%;
/* already defined !!
div.metadata {
font-size: smaller;
color: $gray-600;
@@ -116,5 +118,6 @@ section.chill-entity {
}
}
}
*/
}
}

View File

@@ -0,0 +1,12 @@
const buildLinkCreate = function(workflowName, relatedEntityClass, relatedEntityId) {
let params = new URLSearchParams();
params.set('entityClass', relatedEntityClass);
params.set('entityId', relatedEntityId);
params.set('workflow', workflowName);
return `/fr/main/workflow/create?`+params.toString();
};
export {
buildLinkCreate,
};

View File

@@ -9,9 +9,10 @@ import Dropdown from 'bootstrap/js/src/dropdown';
import Modal from 'bootstrap/js/dist/modal';
import Collapse from 'bootstrap/js/src/collapse';
import Carousel from 'bootstrap/js/src/carousel';
import Popover from 'bootstrap/js/src/popover';
//
// ACHeaderSlider is a small slider used in banner of AccompanyingCourse Section
// Carousel: ACHeaderSlider is a small slider used in banner of AccompanyingCourse Section
// Initialize options, and show/hide controls in first/last slides
//
let ACHeaderSlider = document.querySelector('#ACHeaderSlider');
@@ -48,3 +49,14 @@ if (ACHeaderSlider) {
}
})
}
//
// Popover: used in workflow breadcrumb,
// (expected in: contextual help, notification-box, workflow-box )
//
const triggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
const popoverList = triggerList.map(function (el) {
return new Popover(el, {
html: true,
});
});

View File

@@ -0,0 +1,49 @@
import { createApp } from "vue";
import PickWorkflowVue from 'ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue';
import ListWorkflowVue from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflow.vue';
// pick workflow
document.querySelectorAll('[data-pick-workflow]')
.forEach(function(el) {
const app = {
components: {
PickWorkflowVue
},
template:
'<pick-workflow-vue ' +
':relatedEntityClass="relatedEntityClass" ' +
':relatedEntityId="relatedEntityId" ' +
':workflowsAvailables="workflowsAvailables" ' +
'></pick-workflow-vue>',
data() {
return {
relatedEntityClass: el.dataset.relatedEntityClass,
relatedEntityId: Number.parseInt(el.dataset.relatedEntityId),
workflowsAvailables: JSON.parse(el.dataset.workflowsAvailables),
}
}
};
createApp(app).mount(el);
})
;
// list workflow
document.querySelectorAll('[data-list-workflows]')
.forEach(function (el) {
const app = {
components: {
ListWorkflowVue,
},
template:
'<list-workflow-vue ' +
':workflows="workflows" ' +
'></list-workflow-vue>',
data() {
return {
workflows: JSON.parse(el.dataset.workflows),
}
}
};
createApp(app).mount(el);
})
;

View File

@@ -0,0 +1,32 @@
import {createApp} from "vue";
import EntityWorkflowVueSubscriber from 'ChillMainAssets/vuejs/_components/EntityWorkflow/EntityWorkflowVueSubscriber.vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
import { appMessages } from 'ChillMainAssets/vuejs/PickEntity/i18n';
const i18n = _createI18n(appMessages);
let containers = document.querySelectorAll('[data-entity-workflow-subscribe]');
containers.forEach(container => {
let app = {
components: {
EntityWorkflowVueSubscriber,
},
template: '<entity-workflow-vue-subscriber :entityWorkflowId="this.entityWorkflowId" :subscriberStep="this.subscriberStep" :subscriberFinal="this.subscriberFinal" @subscriptionUpdated="onUpdate"></entity-workflow-vue-subscriber>',
data() {
return {
entityWorkflowId: Number.parseInt(container.dataset.entityWorkflowId),
subscriberStep: container.dataset.subscribeStep === "1",
subscriberFinal: container.dataset.subscribeFinal === "1",
}
},
methods: {
onUpdate(status) {
this.subscriberStep = status.step;
this.subscriberFinal = status.final;
}
}
}
createApp(app).use(i18n).mount(container);
})

View File

@@ -31,7 +31,7 @@ window.addEventListener('DOMContentLoaded', function(e) {
return {
multiple: isMultiple,
types: JSON.parse(el.dataset.types),
picked,
picked: picked === null ? [] : picked,
uniqid: el.dataset.uniqid,
}
},

View File

@@ -0,0 +1,29 @@
import { createApp } from 'vue';
import OpenWopiLink from 'ChillMainAssets/vuejs/_components/OpenWopiLink';
import {_createI18n} from "ChillMainAssets/vuejs/_js/i18n";
const i18n = _createI18n({});
window.addEventListener('DOMContentLoaded', function (e) {
document.querySelectorAll('span[data-module="wopi-link"]')
.forEach(function (el) {
createApp({
template: '<open-wopi-link :wopiUrl="wopiUrl" :title="title" :type="type" :button="button"></open-wopi-link>',
components: {
OpenWopiLink
},
data() {
return {
wopiUrl: el.dataset.wopiUrl,
title: el.dataset.docTitle,
type: el.dataset.docType,
button: el.dataset.button ? JSON.parse(el.dataset.button) : {}
}
}
})
.use(i18n)
.mount(el)
;
})
;
});

View File

@@ -0,0 +1,30 @@
import {ShowHide} from 'ChillMainAssets/lib/show_hide/show_hide.js';
window.addEventListener('DOMContentLoaded', function() {
let
finalizeAfterContainer = document.querySelector('#finalizeAfter'),
futureDestUsersContainer = document.querySelector('#futureDestUsers')
;
if (null === finalizeAfterContainer) {
return;
}
new ShowHide({
load_event: null,
froms: [finalizeAfterContainer],
container: [futureDestUsersContainer],
test: function(containers, arg2, arg3) {
for (let container of containers) {
for (let input of container.querySelectorAll('input')) {
if (!input.checked) {
return true;
} else {
return false;
}
}
}
},
})
});

View File

@@ -0,0 +1,101 @@
<template>
<div class="d-grid gap-2 my-3">
<button class="btn btn-misc" type="button" v-if="!subscriberFinal" @click="subscribeTo('subscribe', 'final')">
<i class="fa fa-check fa-fw"></i>
{{ $t('subscribe_final') }}
</button>
<button class="btn btn-misc" type="button" v-if="subscriberFinal" @click="subscribeTo('unsubscribe', 'final')">
<i class="fa fa-times fa-fw"></i>
{{ $t('unsubscribe_final') }}
</button>
<button class="btn btn-misc" type="button" v-if="!subscriberStep" @click="subscribeTo('subscribe', 'step')">
<i class="fa fa-check fa-fw"></i>
{{ $t('subscribe_all_steps') }}
</button>
<button class="btn btn-misc" type="button" v-if="subscriberStep" @click="subscribeTo('unsubscribe', 'step')">
<i class="fa fa-times fa-fw"></i>
{{ $t('unsubscribe_all_steps') }}
</button>
</div>
</template>
<script>
import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods.js';
export default {
name: "EntityWorkflowVueSubscriber",
i18n: {
messages: {
fr: {
subscribe_final: "Recevoir une notification à l'étape finale",
unsubscribe_final: "Ne plus recevoir de notification à l'étape finale",
subscribe_all_steps: "Recevoir une notification à chaque étape du suivi",
unsubscribe_all_steps: "Ne plus recevoir de notification à chaque étape du suivi",
}
}
},
props: {
entityWorkflowId: {
type: Number,
required: true,
},
subscriberStep: {
type: Boolean,
required: true,
},
subscriberFinal: {
type: Boolean,
required: true,
},
},
emits: ['subscriptionUpdated'],
methods: {
subscribeTo(step, to) {
let params = new URLSearchParams();
params.set('subscribe', to);
const url = `/api/1.0/main/workflow/${this.entityWorkflowId}/${step}?` + params.toString();
makeFetch('POST', url).then(response => {
this.$emit('subscriptionUpdated', response);
});
}
},
}
/*
* ALTERNATIVES
*
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="laststep">
<label class="form-check-label" for="laststep">{{ $t('subscribe_final') }}</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="allsteps">
<label class="form-check-label" for="allsteps">{{ $t('subscribe_all_steps') }}</label>
</div>
<div class="list-group my-3">
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
{{ $t('subscribe_final') }}
</label>
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
{{ $t('subscribe_all_steps') }}
</label>
</div>
<div class="btn-group-vertical my-3" role="group">
<button type="button" class="btn btn-outline-primary">
<i class="fa fa-check fa-fw"></i>
{{ $t('subscribe_final') }}
</button>
<button type="button" class="btn btn-outline-primary">
<i class="fa fa-check fa-fw"></i>
{{ $t('subscribe_all_steps') }}
</button>
</div>
*/
</script>
<style scoped></style>

View File

@@ -0,0 +1,36 @@
<template>
<div class="list-group my-2 workflow workflow-box">
<div class="list-group-item">
<h4>Workflow associés</h4>
</div>
<div class="list-group-item" v-for="w in workflows">
{{ w.id }}
<ul class="record_actions">
<li>
<a class="btn btn-sm btn-outline-primary"
title="voir"
:href="goToUrl(w)">
<i class="fa fa-eye fa-fw"></i>
</a>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: "ListWorkflow",
props: {
workflows: {
type: Array,
required: true,
}
},
methods: {
goToUrl(w) {
return `/fr/main/workflow/${w.id}/show`;
}
}
}
</script>

View File

@@ -0,0 +1,50 @@
<template>
<template v-if="workflowsAvailables.length >= 1">
<div class="dropdown d-grid gap-2">
<button class="btn btn-primary dropdown-toggle" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
Créer un workflow
</button>
<ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
<li v-for="w in workflowsAvailables" :key="w.name">
<a class="dropdown-item" :href="makeLink(w.name)" @click="goToGenerateWorkflow($event, w.name)">{{ w.text }}</a>
</li>
</ul>
</div>
</template>
</template>
<script>
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api.js';
export default {
name: "PickWorkflow",
props: {
relatedEntityClass: {
type: String,
required: true,
},
relatedEntityId: {
type: Number,
required: false,
},
workflowsAvailables: {
type: Array,
required: true,
}
},
emits: ['goToGenerateWorkflow'],
methods: {
makeLink(workflowName) {
return buildLinkCreate(workflowName, this.relatedEntityClass, this.relatedEntityId);
},
goToGenerateWorkflow(event, workflowName) {
this.$emit('goToGenerateWorkflow', {event, workflowName, link: this.makeLink(workflowName)});
}
}
}
</script>
<style scoped>
</style>

View File

@@ -15,7 +15,7 @@
<div class="modal-body">
<slot name="body"></slot>
</div>
<div class="modal-footer">
<div class="modal-footer" v-if="!hideFooter">
<button class="btn btn-cancel" @click="$emit('close')">{{ $t('action.close') }}</button>
<slot name="footer"></slot>
</div>
@@ -38,7 +38,16 @@
*/
export default {
name: 'Modal',
props: ['modalDialogClass'],
props: {
modalDialogClass: {
type: String,
required: false
},
hideFooter: {
type: Boolean,
required: false
}
},
emits: ['close']
}
</script>

View File

@@ -0,0 +1,243 @@
<template>
<a v-if="isOpenDocument"
class="btn change-icon" :class="[isChangeClass ? button.changeClass : 'btn-edit']"
@click="openModal">
<i class="fa me-2" :class="[isChangeIcon ? button.changeIcon : 'fa-pencil']"></i>
<span v-if="!noText">
{{ $t('Update_document') }}
</span>
</a>
<teleport to="body">
<div class="wopi-frame" v-if="isOpenDocument">
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
:hideFooter=true
@close="modal.showModal = false">
<template v-slot:header>
<img class="logo" :src="logo" height="45"/>
<span class="ms-auto me-3">
{{ this.title }}
</span>
<a class="btn btn-outline-light">
<i class="fa fa-save fa-fw"></i>
{{ $t('save_and_quit') }}
</a>
</template>
<template v-slot:body>
<div v-if="loading" class="loading">
<i class="fa fa-circle-o-notch fa-spin fa-3x" :title="$t('loading')"></i>
</div>
<iframe
:src="this.wopiUrl"
@load="loaded"
></iframe>
</template>
</modal>
</div>
<div v-else>
<modal v-if="modal.showModal"
modalDialogClass="modal-sm"
@close="modal.showModal = false">
<template v-slot:header>
<h3>{{ $t('invalid_title') }}</h3>
</template>
<template v-slot:body>
<div class="alert alert-warning">{{ $t('invalid_message') }}</div>
</template>
</modal>
</div>
</teleport>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import logo from 'ChillMainAssets/chill/img/logo-chill-sans-slogan_white.png';
export default {
name: "OpenWopiLink",
components: {
Modal
},
props: {
wopiUrl: {
type: String,
required: true
},
title: {
type: String,
required: true
},
type: {
type: String,
required: true
},
button: {
type: Object,
required: false
}
},
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-fullscreen" //modal-dialog-scrollable
},
logo: logo,
loading: false,
mime: [
// TODO temporary hardcoded. to be replaced by twig extension or a collabora server query
'application/clarisworks',
'application/coreldraw',
'application/macwriteii',
'application/msword',
'application/pdf',
'application/vnd.lotus-1-2-3',
'application/vnd.ms-excel',
'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'application/vnd.ms-excel.sheet.macroEnabled.12',
'application/vnd.ms-excel.template.macroEnabled.12',
'application/vnd.ms-powerpoint',
'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'application/vnd.ms-powerpoint.template.macroEnabled.12',
'application/vnd.ms-visio.drawing',
'application/vnd.ms-word.document.macroEnabled.12',
'application/vnd.ms-word.template.macroEnabled.12',
'application/vnd.ms-works',
'application/vnd.oasis.opendocument.chart',
'application/vnd.oasis.opendocument.formula',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-flat-xml',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-flat-xml',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-flat-xml',
'application/vnd.oasis.opendocument.spreadsheet-template',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-flat-xml',
'application/vnd.oasis.opendocument.text-master',
'application/vnd.oasis.opendocument.text-master-template',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.text-web',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'application/vnd.openxmlformats-officedocument.presentationml.template',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'application/vnd.sun.xml.calc',
'application/vnd.sun.xml.calc.template',
'application/vnd.sun.xml.chart',
'application/vnd.sun.xml.draw',
'application/vnd.sun.xml.draw.template',
'application/vnd.sun.xml.impress',
'application/vnd.sun.xml.impress.template',
'application/vnd.sun.xml.math',
'application/vnd.sun.xml.writer',
'application/vnd.sun.xml.writer.global',
'application/vnd.sun.xml.writer.template',
'application/vnd.visio',
'application/vnd.visio2013',
'application/vnd.wordperfect',
'application/x-abiword',
'application/x-aportisdoc',
'application/x-dbase',
'application/x-dif-document',
'application/x-fictionbook+xml',
'application/x-gnumeric',
'application/x-hwp',
'application/x-iwork-keynote-sffkey',
'application/x-iwork-numbers-sffnumbers',
'application/x-iwork-pages-sffpages',
'application/x-mspublisher',
'application/x-mswrite',
'application/x-pagemaker',
'application/x-sony-bbeb',
'application/x-t602',
]
}
},
computed: {
isOpenDocument() {
if (this.mime.indexOf(this.type) !== -1) {
return true;
}
return false;
},
noText() {
if (typeof this.button.noText !== 'undefined') {
return this.button.noText === true;
}
return false;
},
isChangeIcon() {
if (typeof this.button.changeIcon !== 'undefined') {
return (!(this.button.changeIcon === null || this.button.changeIcon === ''))
}
return false;
},
isChangeClass() {
if (typeof this.button.changeClass !== 'undefined') {
return (!(this.button.changeClass === null || this.button.changeClass === ''))
}
return false;
}
},
methods: {
openModal() {
this.loading = true;
this.modal.showModal = true;
},
loaded() {
this.loading = false;
}
},
i18n: {
messages: {
fr: {
Update_document: "Modifier le document",
save_and_quit: "Enregistrer et quitter",
loading: "Chargement de l'éditeur en ligne",
invalid_title: "Format incompatible",
invalid_message: "Désolé, ce format de document n'est pas éditable en ligne.",
}
}
}
}
</script>
<style lang="scss">
div.wopi-frame {
div.modal-header {
border-bottom: 0;
background-color: var(--bs-primary);
color: white;
}
div.modal-body {
padding: 0;
overflow-y: unset !important;
iframe {
height: 100%;
width: 100%;
}
div.loading {
position: absolute;
color: var(--bs-chill-gray);
top: calc(50% - 30px);
left: calc(50% - 30px);
}
}
}
</style>

View File

@@ -3,7 +3,7 @@
{% block navigation_search_bar %}{% endblock %}
{% block navigation_section_menu %}
{{ chill_menu('admin_section', {
'layout': '@ChillMain/Menu/adminSection.html.twig',
'layout': '@ChillMain/Menu/admin.html.twig',
}) }}
{% endblock %}

View File

@@ -23,23 +23,23 @@
{% if options['metadata'] %}
<div class="metadata">
{% if user is not empty %}
{{ 'Last updated by'| trans }}
<span class="user">
{{ user|chill_entity_render_box(options['user']) }}
</span>
{% endif %}
{% if comment.date is not empty %}
{% if user is empty %}
{{ 'Last updated on'|trans ~ ' ' }}
{% else %}
{{ 'on'|trans ~ ' ' }}
{% endif %}
{{ 'Last updated on'|trans ~ ' ' }}
<span class="date">
{{ comment.date|format_datetime("medium", "short") }}
</span>
{% endif %}
{% if user is not empty %}
{% if comment.date is empty %}
{{ 'Last updated by'| trans }}
{% else %}
{{ 'by_user'|trans ~ ' ' }}
{% endif %}
<span class="user">
{{ user|chill_entity_render_box(options['user']) }}
</span>
{% endif %}
</div>
{% endif %}
</blockquote>
{{ closing_box|raw }}
{{ closing_box|raw }}

View File

@@ -21,13 +21,13 @@
layout ../layoutWithVerticalMenu.html.twig.
#}
<ul class="tab-nav follow-href-path">
<li class="title">
<div class="list-group vertical-menu {{ 'menu-' ~ menus.name }}">
<a class="list-group-item title">
{% block v_menu_title %}<!-- title of the verticalMenu is empty -->{% endblock %}
</li>
</a>
{% for menu in menus %}
<li class="{% if menu is knp_menu_current %}current {% endif %}">
<a href="{{ menu.uri }}" >{{ menu.label|trans }}</a>
</li>
<a class="list-group-item list-group-item-action" href="{{ menu.uri }}">
{{ menu.label|upper }}
</a>
{% endfor %}
</ul>
</div>

View File

@@ -2,7 +2,7 @@
<div class="item-row title">
<h2 class="notification-title">
<a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}">
{{ 'notification.object_prefix'|trans ~ c.notification.title }}
{{ c.notification.title }}
</a>
</h2>
</div>
@@ -58,7 +58,7 @@
</div>
<div class="item-row">
<div class="notification-content">
{% if c.full_content is defined and c.full_content == 'true' %}
{% if c.full_content is defined and c.full_content == true %}
{{ c.notification.message|chill_markdown_to_html }}
{% else %}
{{ c.notification.message|u.truncate(250, '…', false)|chill_markdown_to_html }}
@@ -66,7 +66,7 @@
{% endif %}
</div>
</div>
{% if c.action_button is not defined or c.action_button != 'false' %}
{% if c.action_button is not defined or c.action_button != false %}
<div class="item-row separator">
<ul class="record_actions">
<li>
@@ -102,7 +102,7 @@
<div class="item-bloc notification-status {% if notification.isReadBy(app.user) %}read{% else %}unread{% endif %}">
{% if fold_item is defined and fold_item != 'false' %}
{% if fold_item is defined and fold_item != false %}
<div class="accordion-header" id="flush-heading-{{ notification.id }}">
<button type="button" class="accordion-button collapsed"
data-bs-toggle="collapse" data-bs-target="#flush-collapse-{{ notification.id }}"

View File

@@ -1,2 +1,12 @@
{% if counter.total > 0 %}<span class="badge rounded-pill bg-primary">{{ 'notification.counter total notifications'|trans({'total': counter.total }) }}</span>{% endif %}
{% if counter.unread > 0 %}<span class="badge rounded-pill bg-danger">{{ 'notification.counter unread notifications'|trans({'unread': counter.unread })}}</span>{% endif %}
<div class="notification-counter">
{% if counter.total > 0 %}
<span>
{{ 'notification.counter total notifications'|trans({'total': counter.total }) }}
</span>
{% endif %}
{% if counter.unread > 0 %}
<span>
{{ 'notification.counter unread notifications'|trans({'unread': counter.unread }) }}
</span>
{% endif %}
</div>

View File

@@ -50,7 +50,7 @@
{% for data in datas %}
{% set notification = data.notification %}
{% include 'ChillMainBundle:Notification:_list_item.html.twig' with {
'fold_item': 'true'
'fold_item': true
} %}
{% endfor %}
</div>

View File

@@ -40,8 +40,8 @@
'template': handler.getTemplate(notification),
'template_data': handler.getTemplateData(notification)
},
'action_button': 'false',
'full_content': 'true'
'action_button': false,
'full_content': true
} %}
</div>

View File

@@ -0,0 +1,120 @@
{# TODO Adapt condition #}
{% if random(1) == 0 %}
{# For a document #}
<h2>{{ 'Document'|trans ~ 'target'|trans }}</h2>
<div class="row justify-content-center mt-5">
<div class="col-2">
<i class="fa fa-4x fa-file-text-o text-success"></i>
</div>
<div class="col-8">
<h3>Imprimé unique, parcours n°14635</h3>
<small>Document PDF (6.2 Mo)</small>
<p class="mt-2">
Description du document. Sed euismod nisi porta lorem mollis aliquam. Non curabitur gravida arcu ac tortor.
</p>
</div>
</div>
{% else %}
{# For an action #}
<h2>{{ 'Accompanying Course Action'|trans ~ 'target'|trans }}</h2>
<div class="flex-table accompanying_course_work-list">
{# dynamic insertion
::: TODO delete all static insertion, remove condition and pass work object in inclusion
#}{% if dynamic is defined %}
{% set work = '<pass work object here>' %}
{% include '@ChillPerson/AccompanyingCourseWork/_item.html.twig' with { 'w': work } %}
{% else %}
{# BEGIN static insertion #}
<div class="item-bloc">
<div class="item-row">
<h2 class="badge-title">
<span class="title_label"></span>
<span class="title_action">Exercer un AEB &gt; Conclure l'AEB
<ul class="small_in_title columns mt-1">
<li><span class="item-key">Date de début : </span><b>25/11/2021</b></li>
<li><span class="item-key">Date de fin : </span><b>10/03/2022</b></li>
</ul>
</span>
</h2>
</div>
<div class="item-row separator">
<div class="wrap-list">
<div class="wl-row">
<div class="wl-col title"><h3>Référent</h3></div>
<div class="wl-col list"><p class="wl-item">Fred</p></div>
</div>
<div class="wl-row">
<div class="wl-col title"><h3>Usagers du parcours</h3></div>
<div class="wl-col list"><span class="wl-item">
<span class="onthefly-container" data-target-name="person" data-target-id="1937" data-action="show" data-button-text="Vernon SUBUTEX" data-display-badge="true" data-v-app=""><a data-v-0c1a1125=""><span class="chill-entity entity-person badge-person" data-v-0c1a1125="">Vernon SUBUTEX</span></a><!--teleport start--><!--teleport end--></span></span>
<span class="wl-item"><span class="onthefly-container" data-target-name="person" data-target-id="1941" data-action="show" data-button-text="Juan RAMON" data-display-badge="true" data-v-app=""><a data-v-0c1a1125=""><span class="chill-entity entity-person badge-person" data-v-0c1a1125="">Juan RAMON</span></a><!--teleport start--><!--teleport end--></span></span>
</div>
</div>
<div class="wl-row">
<div class="wl-col title"><h3>Problématique sociale</h3></div>
<div class="wl-col list">
<p class="wl-item social-issues">
<span class="chill-entity entity-social-issue"><span class="badge bg-chill-l-gray text-dark"><span class="parent-0">AD - PREVENTION, ACCES AUX DROITS, BUDGET &gt;</span><span class="child">SOUTIEN EQUILIBRE BUDGET</span></span></span>
</p>
</div>
</div>
</div>
</div>
<div class="item-row column">
<table class="obj-res-eval my-3">
<thead>
<tr><th class="obj"><h4 class="title_label">Objectif - motif - dispositif</h4></th>
<th class="res"><h4 class="title_label">Résultats - orientations</h4></th>
</tr></thead>
<tbody>
<tr>
<td class="obj">
<p class="chill-no-data-statement">Aucun objectif - motif - dispositif</p>
</td>
<td class="res">
<ul class="result_list">
<li>Résultat : Arrêt à l'initiative du ménage pour déménagement</li>
<li>Orientation vers une MASP</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div class="item-row separator">
<div class="updatedBy">
Dernière mise à jour par
<b><span class="chill-entity entity-user">Fred<span class="user-job">(Responsable tous les territoires)</span><span class="main-scope">(ASE)</span></span></b>,<br>
le 3 décembre 2021 à 15:19
</div>
</div>
</div>
{# END static insertion #}
{% endif %}
</div>
{% endif %}
<ul class="record_actions">
<li>
<button type="button" class="btn btn-misc">
<i class="fa fa-download fa-fw"></i>{{ 'Download'|trans }}
</button>
</li>
<li>
{% set x = random(1) %}
<button class="btn btn-update change-icon {% if x == 1 %}disabled{% endif %}">
<i class="fa fa-fw fa-{% if x == 0 %}un{% endif %}lock"></i>
{{ 'Edit'|trans }}
</button>
</li>
</ul>

View File

@@ -0,0 +1,13 @@
<h2>{{ 'Join a comment'|trans }}</h2>
{{ form_start(comment_form) }}
{{ form_widget(comment_form.comment) }}
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(comment_form) }}

View File

@@ -0,0 +1,48 @@
<h2>{{ 'Decision'|trans }}</h2>
{% if transition_form is not null %}
{{ form_start(transition_form) }}
{{ form_row(transition_form.transition) }}
<div id="finalizeAfter">
{{ form_row(transition_form.finalizeAfter) }}
</div>
{% if transition_form.freezeAfter is defined %}
{{ form_row(transition_form.freezeAfter) }}
{% endif %}
<div id="futureDestUsers">
{{ form_row(transition_form.future_dest_users) }}
</div>
<p>{{ form_label(transition_form.comment) }}</p>
{{ form_widget(transition_form.comment) }}
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(transition_form) }}
{% else %}
<div class="alert alert-chill-yellow">
{% if entity_workflow.currentStep.isFinalizeAfter %}
<p>{{ 'workflow.This workflow is finalized'|trans }}</p>
{% else %}
<p>{{ 'workflow.You are not allowed to apply a transition on this workflow'|trans }}</p>
<p>{{ 'workflow.Only those users are allowed'|trans }}:</p>
<ul>
{% for u in entity_workflow.currentStep.destUser -%}
<li>{{ u|chill_entity_render_box }}</li>
{%- endfor %}
</ul>
{% endif %}
</div>
{% endif %}

View File

@@ -0,0 +1,13 @@
{% if is_granted('CHILL_MAIN_WORKFLOW_CREATE', blank_workflow) %}
{# vue component #}
<div data-pick-workflow="1"
data-related-entity-class="{{ blank_workflow.relatedEntityClass }}"
data-related-entity-id="{{ blank_workflow.relatedEntityId }}"
data-workflows-availables="{{ workflows_availables|json_encode()|e('html_attr') }}"
></div>
{% endif %}
{% if entity_workflows|length > 0 %}
{# vue component #}
<div data-list-workflows="1" data-workflows="{{ entity_workflows_json|json_encode|e('html_attr') }}"></div>
{% endif %}

View File

@@ -0,0 +1,8 @@
<h2>{{ 'Follow workflow'|trans }}</h2>
{# vue component #}
<div data-entity-workflow-subscribe="1"
data-entity-workflow-id="{{ entity_workflow.id }}"
data-subscribe-step="{{ entity_workflow.isUserSubscribedToStep(app.user)|e('html_attr') }}"
data-subscribe-final="{{ entity_workflow.isUserSubscribedToFinal(app.user)|e('html_attr') }}"
></div>

View File

@@ -0,0 +1,59 @@
<h2>{{ 'Workflow history'|trans }}</h2>
<div class="flex-table">
{% for step in entity_workflow.stepsChained %}
<div class="item-bloc {{ 'bloc' ~ step.id }} {% if loop.first %}initial{% endif %}">
<div class="item-row">
{% if loop.first and step.next is null %}
<div class="item-col">
{{ 'workflow.No transitions'|trans }}
</div>
{% endif %}
<div class="item-col flex-column align-items-end">
<div class="decided">
{% if not loop.first %}
<i class="fa fa-check fa-fw text-success"></i>
{% endif %}
{{ step.currentStep }}
</div>
{#
<div class="decided">
<i class="fa fa-times fa-fw text-danger"></i>
Refusé
</div>
#}
</div>
</div>
{% if step.next is not null %}
<div class="item-row separator">
<div class="item-col" style="width: inherit;">
{% if step.transitionBy is not null %}
<div>
{{ step.transitionBy|chill_entity_render_box }}
</div>
{% endif %}
<div>
<span>{{ step.transitionAt|format_datetime('long', 'medium') }}</span>
</div>
</div>
<div class="item-col flex-column align-items-end">
<div class="to-decision">
<i class="fa fa-share fa-fw text-secondary" title="transféré"></i>
{{ step.next.currentStep }}
</div>
</div>
</div>
{% endif %}
{% if step.comment is not empty %}
<div class="item-row separator">
<blockquote class="chill-user-quote col">
{{ step.comment|chill_markdown_to_html }}
</blockquote>
</div>
{% endif %}
</div>
{% endfor %}
</div>

View File

@@ -0,0 +1,12 @@
<div class="item-row col">
<h2>
{{ 'workflow_'|trans }}
</h2>
{% include handler.templateTitle(l.entity_workflow) with handler.templateTitleData(entity_workflow)|merge({
'description': true,
'breadcrumb': true,
'add_classes': 'ms-3 h3'
}) %}
</div>

View File

@@ -0,0 +1,56 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
{{ 'Workflow'|trans }}
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_entity_workflow_subscribe') }}
{{ encore_entry_script_tags('page_workflow_show') }}
{{ encore_entry_script_tags('mod_wopi_link') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('mod_entity_workflow_subscribe') }}
{{ encore_entry_link_tags('page_workflow_show') }}
{{ encore_entry_link_tags('mod_wopi_link') }}
{% endblock %}
{% block content %}
<div class="col-10 workflow">
<h1 class="mb-5">{{ block('title') }}</h1>
{# handler_template:
- src/Bundle/ChillPersonBundle/Resources/views/Workflow/_evaluation.html.twig
- src/Bundle/ChillPersonBundle/Resources/views/Workflow/_accompanying_period_work.html.twig
- src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/_workflow.html.twig
#}
<section class="step my-4">
<div class="mb-5">
{% include handler_template_title with handler_template_data|merge({'breadcrumb': true }) %}
</div>
{% include handler_template with handler_template_data|merge({'display_action': true }) %}
</section>
<section class="step my-4">{% include '@ChillMain/Workflow/_follow.html.twig' %}</section>
<section class="step my-4">{% include '@ChillMain/Workflow/_decision.html.twig' %}</section>{#
<section class="step my-4">{% include '@ChillMain/Workflow/_comment.html.twig' %}</section> #}
<section class="step my-4">{% include '@ChillMain/Workflow/_history.html.twig' %}</section>
{# useful ?
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href="{{ path('chill_main_workflow_list_dest') }}">
{{ 'Back to the list'|trans }}
</a>
</li>
</ul>
#}
</div>
{% endblock %}

View File

@@ -0,0 +1,97 @@
{% extends 'ChillMainBundle::layout.html.twig' %}
{% import '@ChillMain/Workflow/macro_breadcrumb.html.twig' as macro %}
{% block title %}
{{ 'workflow.My workflows'|trans }}
{% endblock %}
{% block content %}
<div class="col-10 workflow">
<h1 class="mb-5">{{ block('title') }}</h1>
<ul class="nav nav-pills justify-content-center">
<li class="nav-item">
<a href="{{ path('chill_main_workflow_list_subscribed') }}"
class="nav-link {% if step == 'subscribed' %}active{% endif %}">
{{ 'workflow.subscribed'|trans }}
</a>
</li>
<li class="nav-item">
<a href="{{ path('chill_main_workflow_list_dest') }}"
class="nav-link {% if step == 'dest' %}active{% endif %}">
{{ 'workflow.dest'|trans }}
</a>
</li>
</ul>
{% if workflows|length == 0 %}
<p class="chill-no-data-statement">{{ 'workflow.No workflow'|trans }}</p>
{% else %}
<div class="flex-table accordion accordion-flush" id="workflow-fold">
{% for l in workflows %}
<div class="item-bloc">
<div class="accordion-header" id="flush-heading-{{ l.entity_workflow.id }}">
<button type="button" class="accordion-button collapsed"
data-bs-toggle="collapse" data-bs-target="#flush-collapse-{{ l.entity_workflow.id }}"
aria-expanded="false" aria-controls="flush-collapse-{{ l.entity_workflow.id }}">
<div class="item-row col">
<h2>
{{ 'workflow_'|trans }}
</h2>
{% include l.handler.templateTitle(l.entity_workflow) with l.handler.templateTitleData(l.entity_workflow)|merge({
'description': true,
'add_classes': 'ms-3 h3'
}) %}
</div>
</button>
{{ macro.breadcrumb(l) }}
</div>
<div id="flush-collapse-{{ l.entity_workflow.id }}"
class="accordion-collapse collapse"
aria-labelledby="flush-heading-{{ l.entity_workflow.id }}"
data-bs-parent="#workflow-fold">
<div class="item-row flex-column">
{% include l.handler.template(l.entity_workflow) with l.handler.templateData(l.entity_workflow)|merge({
'display_action': false
}) %}
</div>
<div class="item-row">
<div class="item-col flex-grow-1">
<p>
{% if l.entity_workflow.isUserSubscribedToStep(app.user) %}
<i class="fa fa-check fa-fw"></i>
{{ 'workflow.you subscribed to all steps'|trans }}
{% endif %}
</p>
<p>
{% if l.entity_workflow.isUserSubscribedToFinal(app.user) %}
<i class="fa fa-check fa-fw"></i>
{{ 'workflow.you subscribed to final step'|trans }}
{% endif %}
</p>
</div>
<div class="item-col">
<ul class="record_actions">
<li>
<a href="{{ path('chill_main_workflow_show', {'id': l.entity_workflow.id}) }}"
class="btn btn-show">
{{ 'Show'|trans }}
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,45 @@
{% macro popoverContent(step) %}
<ul class="small_in_title">
<li>
<span class="item-key">{{ 'By'|trans ~ ' : ' }}</span>
<b>{{ step.transitionBy|chill_entity_render_box }}</b>
</li>
<li>
<span class="item-key">{{ 'Le'|trans ~ ' : ' }}</span>
<b>{{ step.transitionAt|format_datetime('short', 'short') }}</b>
</li>
</ul>
{% endmacro %}
{% macro breadcrumb(_ctx) %}
<div class="breadcrumb">
{% for step in _ctx.entity_workflow.stepsChained %}
{% if step.previous is null %}
{#
{% set popContent = "Point de départ du workflow" %}
{{ dump(step) }}
#}
{% set popContent = _self.popoverContent(step) %}
{% else %}
{% set popContent = _self.popoverContent(step.previous) %}
{% endif %}
<span class="mx-2"
tabindex="0"
data-bs-trigger="focus hover"
data-bs-toggle="popover"
data-bs-placement="bottom"
data-bs-custom-class="workflow-transition"
title="{{ step.currentStep }}"
data-bs-content="{{ popContent|e('html_attr') }}"
>
{% if step.currentStep == 'initial' %}
<i class="fa fa-circle me-1 text-chill-yellow"></i>
{% endif %}
{{ step.currentStep }}
</span>
{% if not loop.last %}
{% endif %}
{% endfor %}
</div>
{% endmacro %}

View File

@@ -0,0 +1,13 @@
{{ dest.label }},
Un suivi "{{ workflow.text }}" a atteint une nouvelle étape: {{ workflow.text }}
{%- if is_dest %}
Vous êtes invités à valider cette étape au plus tôt.
{% endif %}
Vous pouvez visualiser le workflow sur cette page:
{{ absolute_url(path('chill_main_workflow_show', {'id': entity_workflow.id})) }}
Cordialement,

View File

@@ -0,0 +1,5 @@
{%- if is_dest -%}
Un suivi {{ workflow.text }} demande votre attention
{%- else -%}
Un suivi {{ workflow.text }} a atteint une nouvelle étape: {{ place.text }}
{%- endif -%}