mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 11:18:25 +00:00 
			
		
		
		
	Compare commits
	
		
			123 Commits
		
	
	
		
			refactor_a
			...
			321-text-e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						b5c9e65986
	
				 | 
					
					
						|||
| 
						
						
							
						
						8b2af35e97
	
				 | 
					
					
						|||
| dc44c46667 | |||
| ba571c1a69 | |||
| 6a364705f2 | |||
| b6d454691a | |||
| 6d7a6932a9 | |||
| 
						 | 
					2faf194b15 | ||
| f207599d86 | |||
| b0959f8cc5 | |||
| 4c5dee5f0a | |||
| f6c98aa0d5 | |||
| 6d13d184d5 | |||
| af36eccfaf | |||
| 483a20a43f | |||
| 6d8e2ad825 | |||
| 86388a63a8 | |||
| 
						 | 
					5ea55ebfe5 | ||
| f97dc8f931 | |||
| 
						 | 
					a9c3aab528 | ||
| 1181377bd6 | |||
| 
						 | 
					2275b7c560 | ||
| 4a8d298ae5 | |||
| 
						
						
							
						
						3e7f03d331
	
				 | 
					
					
						|||
| 
						
						
							
						
						b830952b9e
	
				 | 
					
					
						|||
| ad17313c61 | |||
| 
						
						
							
						
						620515ad15
	
				 | 
					
					
						|||
| 50c377ee22 | |||
| cc7e7a90ee | |||
| 
						
						
							
						
						1d4ef19051
	
				 | 
					
					
						|||
| 
						
						
							
						
						8337a724d1
	
				 | 
					
					
						|||
| 8ca377d5d4 | |||
| 224e0bae43 | |||
| 3aa4fac80d | |||
| 
						 | 
					a7517eb647 | ||
| e278e636e0 | |||
| 
						 | 
					40e373a9c7 | ||
| 1c1f418b18 | |||
| bf0e14b43a | |||
| 
						
						
							
						
						203a098054
	
				 | 
					
					
						|||
| 
						
						
							
						
						d58acff541
	
				 | 
					
					
						|||
| 
						
						
							
						
						5858e05a42
	
				 | 
					
					
						|||
| 
						
						
							
						
						b9b4fafe14
	
				 | 
					
					
						|||
| fe6949ea26 | |||
| 8a444a12f4 | |||
| 
						
						
							
						
						8b7b5ceed7
	
				 | 
					
					
						|||
| 
						
						
							
						
						b0e826d05a
	
				 | 
					
					
						|||
| 
						
						
							
						
						6fb9c3af3f
	
				 | 
					
					
						|||
| 
						
						
							
						
						7f101ba616
	
				 | 
					
					
						|||
| cea82fac10 | |||
| 1344fc33e1 | |||
| c8e09a28e6 | |||
| 
						
						
							
						
						c52d4b2a0e
	
				 | 
					
					
						|||
| 
						
						
							
						
						7f326d5441
	
				 | 
					
					
						|||
| 2840c06476 | |||
| 7ddf84ea5a | |||
| 
						
						
							
						
						f202625ea8
	
				 | 
					
					
						|||
| 
						
						
							
						
						7a9168fcdb
	
				 | 
					
					
						|||
| 40eb71f95a | |||
| 84b7cc8145 | |||
| 08af530726 | |||
| 
						
						
							
						
						03b2496817
	
				 | 
					
					
						|||
| f638ce71fd | |||
| b39997f00a | |||
| 38b21a2159 | |||
| 17db571244 | |||
| 8c8c16c1a1 | |||
| 046d3ec9f1 | |||
| 596833f1a5 | |||
| 66e4bab558 | |||
| d1c9926bb1 | |||
| a71d066765 | |||
| 217ac7b9e7 | |||
| be901822bc | |||
| 2dcce7b826 | |||
| 7ed10efcd1 | |||
| 350661a4fa | |||
| 08207b656a | |||
| 8de63de6d6 | |||
| 51804b10c0 | |||
| 02f555efae | |||
| d2fcb6945b | |||
| dcd1777a70 | |||
| a6eb28175a | |||
| c89e3785ef | |||
| 9f17ec4841 | |||
| b277a7749a | |||
| c8b6b6e33a | |||
| 10eaebf610 | |||
| 7d78512823 | |||
| 
						
						
							
						
						0a34f9086f
	
				 | 
					
					
						|||
| 739e0b1692 | |||
| 
						
						
							
						
						8db8f5fdf5
	
				 | 
					
					
						|||
| d0cd4792d6 | |||
| 6d196ead94 | |||
| 4047d5fd5b | |||
| 9aac80d834 | |||
| 7560dc57c6 | |||
| 10314845f6 | |||
| 9b84bc4d69 | |||
| a2fcf039be | |||
| b4d887a372 | |||
| 0aaa7122da | |||
| 1bc7f85874 | |||
| 1d2fd000aa | |||
| fc32f9eca9 | |||
| 
						 | 
					03717a1a87 | ||
| 
						 | 
					02c524dd79 | ||
| 506df432b0 | |||
| c32c18b0e2 | |||
| 321d569ee9 | |||
| cd40eb3932 | |||
| f0f2531fa3 | |||
| 183a220e7b | |||
| 9df127a82c | |||
| 04a1412562 | |||
| 3aef0a185e | |||
| 578bce31b9 | |||
| 
						 | 
					bc7f0907ab | ||
| 
						 | 
					fbdc0d32f0 | ||
| 
						 | 
					5f31473c90 | ||
| 
						 | 
					98cf167040 | ||
| 
						 | 
					6c37d798bf | 
							
								
								
									
										6
									
								
								.changes/unreleased/DX-20250430-144550.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/DX-20250430-144550.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
kind: DX
 | 
			
		||||
body: Remove dead code for wopi-link module
 | 
			
		||||
time: 2025-04-30T14:45:50.406111606+02:00
 | 
			
		||||
custom:
 | 
			
		||||
    Issue: "352"
 | 
			
		||||
    SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										7
									
								
								.changes/unreleased/Feature-20250424-142211.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.changes/unreleased/Feature-20250424-142211.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
kind: Feature
 | 
			
		||||
body: Add the document file name to the document title when a user upload a document,
 | 
			
		||||
  unless there is already a document title.
 | 
			
		||||
time: 2025-04-24T14:22:11.800975422+02:00
 | 
			
		||||
custom:
 | 
			
		||||
  Issue: "377"
 | 
			
		||||
  SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										6
									
								
								.changes/unreleased/Feature-20250520-095628.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Feature-20250520-095628.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
kind: Feature
 | 
			
		||||
body: Add desactivation date for social action and issue csv export
 | 
			
		||||
time: 2025-05-20T09:56:28.108941934+02:00
 | 
			
		||||
custom:
 | 
			
		||||
    Issue: ""
 | 
			
		||||
    SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										7
									
								
								.changes/unreleased/Fixed-20250424-133943.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.changes/unreleased/Fixed-20250424-133943.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
kind: Fixed
 | 
			
		||||
body: trying to prevent bug of typeerror in doc-history + improved display of document
 | 
			
		||||
  history
 | 
			
		||||
time: 2025-04-24T13:39:43.878468232+02:00
 | 
			
		||||
custom:
 | 
			
		||||
  Issue: "376"
 | 
			
		||||
  SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										7
									
								
								.changes/unreleased/Fixed-20250424-163746.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.changes/unreleased/Fixed-20250424-163746.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
kind: Fixed
 | 
			
		||||
body: Display previous participation in acc course work even if the person has left
 | 
			
		||||
  the acc course
 | 
			
		||||
time: 2025-04-24T16:37:46.970203594+02:00
 | 
			
		||||
custom:
 | 
			
		||||
  Issue: "381"
 | 
			
		||||
  SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										6
									
								
								.changes/unreleased/Fixed-20250505-102715.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Fixed-20250505-102715.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
kind: Fixed
 | 
			
		||||
body: Fix display of text in calendar events
 | 
			
		||||
time: 2025-05-05T10:27:15.461493066+02:00
 | 
			
		||||
custom:
 | 
			
		||||
    Issue: "372"
 | 
			
		||||
    SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										6
									
								
								.changes/unreleased/Fixed-20250514-145339.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Fixed-20250514-145339.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
kind: Fixed
 | 
			
		||||
body: Add missing translation for user_group.no_user_groups
 | 
			
		||||
time: 2025-05-14T14:53:39.53927329+02:00
 | 
			
		||||
custom:
 | 
			
		||||
    Issue: ""
 | 
			
		||||
    SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										6
									
								
								.changes/unreleased/UX-20250423-172624.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/UX-20250423-172624.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
kind: UX
 | 
			
		||||
body: Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page
 | 
			
		||||
time: 2025-04-23T17:26:24.45777387+02:00
 | 
			
		||||
custom:
 | 
			
		||||
    Issue: "374"
 | 
			
		||||
    SchemaChange: No schema change
 | 
			
		||||
							
								
								
									
										6
									
								
								.changes/v3.10.0.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/v3.10.0.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
## v3.10.0 - 2025-03-17
 | 
			
		||||
### Feature
 | 
			
		||||
* ([#363](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/363)) Display social actions grouped per social issue within activity form   
 | 
			
		||||
### Fixed
 | 
			
		||||
* ([#362](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/362)) Fix Dependency Injection, which prevented to save the CalendarRange   
 | 
			
		||||
* ([#368](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/368)) fix search query for user groups   
 | 
			
		||||
							
								
								
									
										3
									
								
								.changes/v3.10.1.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.changes/v3.10.1.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
## v3.10.1 - 2025-03-17
 | 
			
		||||
### DX
 | 
			
		||||
* Remove yarn dependency to symfony/ux-translator, to ease the build process
 | 
			
		||||
							
								
								
									
										3
									
								
								.changes/v3.10.2.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.changes/v3.10.2.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
## v3.10.2 - 2025-03-17
 | 
			
		||||
### Fixed
 | 
			
		||||
* Replace a ts-expect-error with a ts-ignore   
 | 
			
		||||
							
								
								
									
										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   
 | 
			
		||||
							
								
								
									
										19
									
								
								.changes/v3.11.0.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.changes/v3.11.0.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
## v3.11.0 - 2025-04-17
 | 
			
		||||
### Feature
 | 
			
		||||
* ([#365](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/365)) Add counters of actions and activities, with 2 boxes to (1) show the number of active actions on total actions and (2) show the number of activities in a accompanying period, and pills in menus for showing the number of active actions and the number of activities.
 | 
			
		||||
* ([#364](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/364)) Added a second phone number "telephone2" to the thirdParty entity. Adapted twig templates and vuejs apps to handle this phone number
 | 
			
		||||
 | 
			
		||||
  **Schema Change**: Add columns or tables
 | 
			
		||||
* Signature: add a button to go directly to the signature zone, even if there is only one
 | 
			
		||||
### Fixed
 | 
			
		||||
* Fixed wrong translations in the on-the-fly for creation of thirdParty
 | 
			
		||||
* Fixed update of phone number in on-the-fly edition of thirdParty
 | 
			
		||||
* Fixed closing of modal when editing thirdParty in accompanying course works
 | 
			
		||||
* Shorten the delay between two execution of AccompanyingPeriodStepChangeCronjob, to ensure at least one execution in a day
 | 
			
		||||
* ([#102](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/102)) Fix display of title in document list
 | 
			
		||||
* When cleaning the old stored object versions, do not throw an error if the stored object is not found on disk
 | 
			
		||||
* Add consistent log prefix and key to logs when stale workflows are automatically canceled
 | 
			
		||||
* ([#380](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/380)) Remove the "not null" validation constraint on recently added properties on HouseholdComposition
 | 
			
		||||
 | 
			
		||||
### DX
 | 
			
		||||
* Add new chill-col style for displaying title and aside in a flex table
 | 
			
		||||
							
								
								
									
										10
									
								
								.changes/v3.9.0.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.changes/v3.9.0.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
## v3.9.0 - 2025-02-27
 | 
			
		||||
### Feature
 | 
			
		||||
* ([#349](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/349)) Suggest all referrers within actions of the accompanying period when creating an activity   
 | 
			
		||||
* ([#343](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/343)) Add possibility to export a csv with all social issues and social actions   
 | 
			
		||||
* ([#360](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/360)) Restore document to previous kept version when a workflow is canceled   
 | 
			
		||||
* ([#341](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/341)) Add a list of third parties from within the admin (csv download)   
 | 
			
		||||
### Fixed
 | 
			
		||||
* fix generation of document with accompanying period context, and list of activities and works   
 | 
			
		||||
### DX
 | 
			
		||||
* ([#333](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/333)) Create an unique source of trust for translations   
 | 
			
		||||
							
								
								
									
										3
									
								
								.changes/v3.9.1.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.changes/v3.9.1.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
## v3.9.1 - 2025-02-27
 | 
			
		||||
### Fixed
 | 
			
		||||
* Fix post/patch request with missing 'type' property for gender   
 | 
			
		||||
							
								
								
									
										3
									
								
								.changes/v3.9.2.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.changes/v3.9.2.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
## v3.9.2 - 2025-02-27
 | 
			
		||||
### Fixed
 | 
			
		||||
* Use fetchResults method to fetch all social issues instead of only the first page   
 | 
			
		||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -12,6 +12,8 @@ docker/rabbitmq/data
 | 
			
		||||
 | 
			
		||||
# in this development bundle, we want to ignore directories related to a real app
 | 
			
		||||
assets/*
 | 
			
		||||
!assets/translator.ts
 | 
			
		||||
!assets/ux-translator
 | 
			
		||||
migrations/*
 | 
			
		||||
templates/*
 | 
			
		||||
translations/*
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,7 @@ lint:
 | 
			
		||||
        - export PATH="./node_modules/.bin:$PATH"
 | 
			
		||||
    script:
 | 
			
		||||
        - yarn install --ignore-optional
 | 
			
		||||
        - npx eslint-baseline "**/*.{js,vue}"
 | 
			
		||||
        - npx eslint-baseline "src/**/*.{js,ts,vue}"
 | 
			
		||||
    cache:
 | 
			
		||||
        paths:
 | 
			
		||||
            - node_modules/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -6,6 +6,44 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
 | 
			
		||||
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
 | 
			
		||||
### Fixed
 | 
			
		||||
* Replace a ts-expect-error with a ts-ignore   
 | 
			
		||||
 | 
			
		||||
## v3.10.1 - 2025-03-17
 | 
			
		||||
### DX
 | 
			
		||||
* Remove yarn dependency to symfony/ux-translator, to ease the build process
 | 
			
		||||
 | 
			
		||||
## v3.10.0 - 2025-03-17
 | 
			
		||||
### Feature
 | 
			
		||||
* ([#363](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/363)) Display social actions grouped per social issue within activity form   
 | 
			
		||||
### Fixed
 | 
			
		||||
* ([#362](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/362)) Fix Dependency Injection, which prevented to save the CalendarRange   
 | 
			
		||||
* ([#368](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/368)) fix search query for user groups   
 | 
			
		||||
 | 
			
		||||
## v3.9.2 - 2025-02-27
 | 
			
		||||
### Fixed
 | 
			
		||||
* Use fetchResults method to fetch all social issues instead of only the first page   
 | 
			
		||||
 | 
			
		||||
## v3.9.1 - 2025-02-27
 | 
			
		||||
### Fixed
 | 
			
		||||
* Fix post/patch request with missing 'type' property for gender   
 | 
			
		||||
 | 
			
		||||
## v3.9.0 - 2025-02-27
 | 
			
		||||
### Feature
 | 
			
		||||
* ([#349](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/349)) Suggest all referrers within actions of the accompanying period when creating an activity   
 | 
			
		||||
* ([#343](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/343)) Add possibility to export a csv with all social issues and social actions   
 | 
			
		||||
* ([#360](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/360)) Restore document to previous kept version when a workflow is canceled   
 | 
			
		||||
* ([#341](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/341)) Add a list of third parties from within the admin (csv download)   
 | 
			
		||||
### Fixed
 | 
			
		||||
* fix generation of document with accompanying period context, and list of activities and works   
 | 
			
		||||
### DX
 | 
			
		||||
* ([#333](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/333)) Create an unique source of trust for translations   
 | 
			
		||||
 | 
			
		||||
## v3.8.2 - 2025-02-10
 | 
			
		||||
### Fixed
 | 
			
		||||
* ([#358](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/358)) Remove "filter" button on list of documents in the workflow's "add attachement" modal   
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								assets/translator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								assets/translator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
import { trans, setLocale, setLocaleFallbacks } from "./ux-translator";
 | 
			
		||||
 | 
			
		||||
setLocaleFallbacks({"en": "fr", "nl": "fr", "fr": "en"});
 | 
			
		||||
setLocale('fr');
 | 
			
		||||
 | 
			
		||||
export { trans };
 | 
			
		||||
export * from '../var/translations';
 | 
			
		||||
							
								
								
									
										3
									
								
								assets/ux-translator/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								assets/ux-translator/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
This directory import the symfony ux-translator files directly into chill-bundles.
 | 
			
		||||
 | 
			
		||||
This remove the yarn dependencies from the real package, which breaks our installation.
 | 
			
		||||
							
								
								
									
										1
									
								
								assets/ux-translator/dist/formatters/formatter.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/ux-translator/dist/formatters/formatter.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export declare function format(id: string, parameters: Record<string, string | number>, locale: string): string;
 | 
			
		||||
							
								
								
									
										1
									
								
								assets/ux-translator/dist/formatters/intl-formatter.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/ux-translator/dist/formatters/intl-formatter.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export declare function formatIntl(id: string, parameters: Record<string, string | number>, locale: string): string;
 | 
			
		||||
							
								
								
									
										27
									
								
								assets/ux-translator/dist/translator.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								assets/ux-translator/dist/translator.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
export type DomainType = string;
 | 
			
		||||
export type LocaleType = string;
 | 
			
		||||
export type TranslationsType = Record<DomainType, {
 | 
			
		||||
    parameters: ParametersType;
 | 
			
		||||
}>;
 | 
			
		||||
export type NoParametersType = Record<string, never>;
 | 
			
		||||
export type ParametersType = Record<string, string | number | Date> | NoParametersType;
 | 
			
		||||
export type RemoveIntlIcuSuffix<T> = T extends `${infer U}+intl-icu` ? U : T;
 | 
			
		||||
export type DomainsOf<M> = M extends Message<infer Translations, LocaleType> ? keyof Translations : never;
 | 
			
		||||
export type LocaleOf<M> = M extends Message<TranslationsType, infer Locale> ? Locale : never;
 | 
			
		||||
export type ParametersOf<M, D extends DomainType> = M extends Message<infer Translations, LocaleType> ? Translations[D] extends {
 | 
			
		||||
    parameters: infer Parameters;
 | 
			
		||||
} ? Parameters : never : never;
 | 
			
		||||
export interface Message<Translations extends TranslationsType, Locale extends LocaleType> {
 | 
			
		||||
    id: string;
 | 
			
		||||
    translations: {
 | 
			
		||||
        [domain in DomainType]: {
 | 
			
		||||
            [locale in Locale]: string;
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
export declare function setLocale(locale: LocaleType | null): void;
 | 
			
		||||
export declare function getLocale(): LocaleType;
 | 
			
		||||
export declare function throwWhenNotFound(enabled: boolean): void;
 | 
			
		||||
export declare function setLocaleFallbacks(localeFallbacks: Record<LocaleType, LocaleType>): void;
 | 
			
		||||
export declare function getLocaleFallbacks(): Record<LocaleType, LocaleType>;
 | 
			
		||||
export declare function trans<M extends Message<TranslationsType, LocaleType>, D extends DomainsOf<M>, P extends ParametersOf<M, D>>(...args: P extends NoParametersType ? [message: M, parameters?: P, domain?: RemoveIntlIcuSuffix<D>, locale?: LocaleOf<M>] : [message: M, parameters: P, domain?: RemoveIntlIcuSuffix<D>, locale?: LocaleOf<M>]): string;
 | 
			
		||||
							
								
								
									
										1
									
								
								assets/ux-translator/dist/translator_controller.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/ux-translator/dist/translator_controller.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export * from './translator';
 | 
			
		||||
							
								
								
									
										283
									
								
								assets/ux-translator/dist/translator_controller.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								assets/ux-translator/dist/translator_controller.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
import { IntlMessageFormat } from 'intl-messageformat';
 | 
			
		||||
 | 
			
		||||
function strtr(string, replacePairs) {
 | 
			
		||||
    const regex = Object.entries(replacePairs).map(([from]) => {
 | 
			
		||||
        return from.replace(/([-[\]{}()*+?.\\^$|#,])/g, '\\$1');
 | 
			
		||||
    });
 | 
			
		||||
    if (regex.length === 0) {
 | 
			
		||||
        return string;
 | 
			
		||||
    }
 | 
			
		||||
    return string.replace(new RegExp(regex.join('|'), 'g'), (matched) => replacePairs[matched].toString());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function format(id, parameters, locale) {
 | 
			
		||||
    if (null === id || '' === id) {
 | 
			
		||||
        return '';
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof parameters['%count%'] === 'undefined' || Number.isNaN(parameters['%count%'])) {
 | 
			
		||||
        return strtr(id, parameters);
 | 
			
		||||
    }
 | 
			
		||||
    const number = Number(parameters['%count%']);
 | 
			
		||||
    let parts = [];
 | 
			
		||||
    if (/^\|+$/.test(id)) {
 | 
			
		||||
        parts = id.split('|');
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        parts = id.match(/(?:\|\||[^|])+/g) || [];
 | 
			
		||||
    }
 | 
			
		||||
    const intervalRegex = /^(?<interval>({\s*(-?\d+(\.\d+)?[\s*,\s*\-?\d+(.\d+)?]*)\s*})|(?<left_delimiter>[[\]])\s*(?<left>-Inf|-?\d+(\.\d+)?)\s*,\s*(?<right>\+?Inf|-?\d+(\.\d+)?)\s*(?<right_delimiter>[[\]]))\s*(?<message>.*?)$/s;
 | 
			
		||||
    const standardRules = [];
 | 
			
		||||
    for (let part of parts) {
 | 
			
		||||
        part = part.trim().replace(/\|\|/g, '|');
 | 
			
		||||
        const matches = part.match(intervalRegex);
 | 
			
		||||
        if (matches) {
 | 
			
		||||
            const matchGroups = matches.groups || {};
 | 
			
		||||
            if (matches[2]) {
 | 
			
		||||
                for (const n of matches[3].split(',')) {
 | 
			
		||||
                    if (number === Number(n)) {
 | 
			
		||||
                        return strtr(matchGroups.message, parameters);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                const leftNumber = '-Inf' === matchGroups.left ? Number.NEGATIVE_INFINITY : Number(matchGroups.left);
 | 
			
		||||
                const rightNumber = ['Inf', '+Inf'].includes(matchGroups.right)
 | 
			
		||||
                    ? Number.POSITIVE_INFINITY
 | 
			
		||||
                    : Number(matchGroups.right);
 | 
			
		||||
                if (('[' === matchGroups.left_delimiter ? number >= leftNumber : number > leftNumber) &&
 | 
			
		||||
                    (']' === matchGroups.right_delimiter ? number <= rightNumber : number < rightNumber)) {
 | 
			
		||||
                    return strtr(matchGroups.message, parameters);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            const ruleMatch = part.match(/^\w+:\s*(.*?)$/);
 | 
			
		||||
            standardRules.push(ruleMatch ? ruleMatch[1] : part);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    const position = getPluralizationRule(number, locale);
 | 
			
		||||
    if (typeof standardRules[position] === 'undefined') {
 | 
			
		||||
        if (1 === parts.length && typeof standardRules[0] !== 'undefined') {
 | 
			
		||||
            return strtr(standardRules[0], parameters);
 | 
			
		||||
        }
 | 
			
		||||
        throw new Error(`Unable to choose a translation for "${id}" with locale "${locale}" for value "${number}". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %count% apples").`);
 | 
			
		||||
    }
 | 
			
		||||
    return strtr(standardRules[position], parameters);
 | 
			
		||||
}
 | 
			
		||||
function getPluralizationRule(number, locale) {
 | 
			
		||||
    number = Math.abs(number);
 | 
			
		||||
    let _locale = locale;
 | 
			
		||||
    if (locale === 'pt_BR' || locale === 'en_US_POSIX') {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    _locale = _locale.length > 3 ? _locale.substring(0, _locale.indexOf('_')) : _locale;
 | 
			
		||||
    switch (_locale) {
 | 
			
		||||
        case 'af':
 | 
			
		||||
        case 'bn':
 | 
			
		||||
        case 'bg':
 | 
			
		||||
        case 'ca':
 | 
			
		||||
        case 'da':
 | 
			
		||||
        case 'de':
 | 
			
		||||
        case 'el':
 | 
			
		||||
        case 'en':
 | 
			
		||||
        case 'en_US_POSIX':
 | 
			
		||||
        case 'eo':
 | 
			
		||||
        case 'es':
 | 
			
		||||
        case 'et':
 | 
			
		||||
        case 'eu':
 | 
			
		||||
        case 'fa':
 | 
			
		||||
        case 'fi':
 | 
			
		||||
        case 'fo':
 | 
			
		||||
        case 'fur':
 | 
			
		||||
        case 'fy':
 | 
			
		||||
        case 'gl':
 | 
			
		||||
        case 'gu':
 | 
			
		||||
        case 'ha':
 | 
			
		||||
        case 'he':
 | 
			
		||||
        case 'hu':
 | 
			
		||||
        case 'is':
 | 
			
		||||
        case 'it':
 | 
			
		||||
        case 'ku':
 | 
			
		||||
        case 'lb':
 | 
			
		||||
        case 'ml':
 | 
			
		||||
        case 'mn':
 | 
			
		||||
        case 'mr':
 | 
			
		||||
        case 'nah':
 | 
			
		||||
        case 'nb':
 | 
			
		||||
        case 'ne':
 | 
			
		||||
        case 'nl':
 | 
			
		||||
        case 'nn':
 | 
			
		||||
        case 'no':
 | 
			
		||||
        case 'oc':
 | 
			
		||||
        case 'om':
 | 
			
		||||
        case 'or':
 | 
			
		||||
        case 'pa':
 | 
			
		||||
        case 'pap':
 | 
			
		||||
        case 'ps':
 | 
			
		||||
        case 'pt':
 | 
			
		||||
        case 'so':
 | 
			
		||||
        case 'sq':
 | 
			
		||||
        case 'sv':
 | 
			
		||||
        case 'sw':
 | 
			
		||||
        case 'ta':
 | 
			
		||||
        case 'te':
 | 
			
		||||
        case 'tk':
 | 
			
		||||
        case 'ur':
 | 
			
		||||
        case 'zu':
 | 
			
		||||
            return 1 === number ? 0 : 1;
 | 
			
		||||
        case 'am':
 | 
			
		||||
        case 'bh':
 | 
			
		||||
        case 'fil':
 | 
			
		||||
        case 'fr':
 | 
			
		||||
        case 'gun':
 | 
			
		||||
        case 'hi':
 | 
			
		||||
        case 'hy':
 | 
			
		||||
        case 'ln':
 | 
			
		||||
        case 'mg':
 | 
			
		||||
        case 'nso':
 | 
			
		||||
        case 'pt_BR':
 | 
			
		||||
        case 'ti':
 | 
			
		||||
        case 'wa':
 | 
			
		||||
            return number < 2 ? 0 : 1;
 | 
			
		||||
        case 'be':
 | 
			
		||||
        case 'bs':
 | 
			
		||||
        case 'hr':
 | 
			
		||||
        case 'ru':
 | 
			
		||||
        case 'sh':
 | 
			
		||||
        case 'sr':
 | 
			
		||||
        case 'uk':
 | 
			
		||||
            return 1 === number % 10 && 11 !== number % 100
 | 
			
		||||
                ? 0
 | 
			
		||||
                : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20)
 | 
			
		||||
                    ? 1
 | 
			
		||||
                    : 2;
 | 
			
		||||
        case 'cs':
 | 
			
		||||
        case 'sk':
 | 
			
		||||
            return 1 === number ? 0 : number >= 2 && number <= 4 ? 1 : 2;
 | 
			
		||||
        case 'ga':
 | 
			
		||||
            return 1 === number ? 0 : 2 === number ? 1 : 2;
 | 
			
		||||
        case 'lt':
 | 
			
		||||
            return 1 === number % 10 && 11 !== number % 100
 | 
			
		||||
                ? 0
 | 
			
		||||
                : number % 10 >= 2 && (number % 100 < 10 || number % 100 >= 20)
 | 
			
		||||
                    ? 1
 | 
			
		||||
                    : 2;
 | 
			
		||||
        case 'sl':
 | 
			
		||||
            return 1 === number % 100 ? 0 : 2 === number % 100 ? 1 : 3 === number % 100 || 4 === number % 100 ? 2 : 3;
 | 
			
		||||
        case 'mk':
 | 
			
		||||
            return 1 === number % 10 ? 0 : 1;
 | 
			
		||||
        case 'mt':
 | 
			
		||||
            return 1 === number
 | 
			
		||||
                ? 0
 | 
			
		||||
                : 0 === number || (number % 100 > 1 && number % 100 < 11)
 | 
			
		||||
                    ? 1
 | 
			
		||||
                    : number % 100 > 10 && number % 100 < 20
 | 
			
		||||
                        ? 2
 | 
			
		||||
                        : 3;
 | 
			
		||||
        case 'lv':
 | 
			
		||||
            return 0 === number ? 0 : 1 === number % 10 && 11 !== number % 100 ? 1 : 2;
 | 
			
		||||
        case 'pl':
 | 
			
		||||
            return 1 === number
 | 
			
		||||
                ? 0
 | 
			
		||||
                : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 12 || number % 100 > 14)
 | 
			
		||||
                    ? 1
 | 
			
		||||
                    : 2;
 | 
			
		||||
        case 'cy':
 | 
			
		||||
            return 1 === number ? 0 : 2 === number ? 1 : 8 === number || 11 === number ? 2 : 3;
 | 
			
		||||
        case 'ro':
 | 
			
		||||
            return 1 === number ? 0 : 0 === number || (number % 100 > 0 && number % 100 < 20) ? 1 : 2;
 | 
			
		||||
        case 'ar':
 | 
			
		||||
            return 0 === number
 | 
			
		||||
                ? 0
 | 
			
		||||
                : 1 === number
 | 
			
		||||
                    ? 1
 | 
			
		||||
                    : 2 === number
 | 
			
		||||
                        ? 2
 | 
			
		||||
                        : number % 100 >= 3 && number % 100 <= 10
 | 
			
		||||
                            ? 3
 | 
			
		||||
                            : number % 100 >= 11 && number % 100 <= 99
 | 
			
		||||
                                ? 4
 | 
			
		||||
                                : 5;
 | 
			
		||||
        default:
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function formatIntl(id, parameters, locale) {
 | 
			
		||||
    if (id === '') {
 | 
			
		||||
        return '';
 | 
			
		||||
    }
 | 
			
		||||
    const intlMessage = new IntlMessageFormat(id, [locale.replace('_', '-')], undefined, { ignoreTag: true });
 | 
			
		||||
    parameters = { ...parameters };
 | 
			
		||||
    Object.entries(parameters).forEach(([key, value]) => {
 | 
			
		||||
        if (key.includes('%') || key.includes('{')) {
 | 
			
		||||
            delete parameters[key];
 | 
			
		||||
            parameters[key.replace(/[%{} ]/g, '').trim()] = value;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    return intlMessage.format(parameters);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let _locale = null;
 | 
			
		||||
let _localeFallbacks = {};
 | 
			
		||||
let _throwWhenNotFound = false;
 | 
			
		||||
function setLocale(locale) {
 | 
			
		||||
    _locale = locale;
 | 
			
		||||
}
 | 
			
		||||
function getLocale() {
 | 
			
		||||
    return (_locale ||
 | 
			
		||||
        document.documentElement.getAttribute('data-symfony-ux-translator-locale') ||
 | 
			
		||||
        (document.documentElement.lang ? document.documentElement.lang.replace('-', '_') : null) ||
 | 
			
		||||
        'en');
 | 
			
		||||
}
 | 
			
		||||
function throwWhenNotFound(enabled) {
 | 
			
		||||
    _throwWhenNotFound = enabled;
 | 
			
		||||
}
 | 
			
		||||
function setLocaleFallbacks(localeFallbacks) {
 | 
			
		||||
    _localeFallbacks = localeFallbacks;
 | 
			
		||||
}
 | 
			
		||||
function getLocaleFallbacks() {
 | 
			
		||||
    return _localeFallbacks;
 | 
			
		||||
}
 | 
			
		||||
function trans(message, parameters = {}, domain = 'messages', locale = null) {
 | 
			
		||||
    if (typeof domain === 'undefined') {
 | 
			
		||||
        domain = 'messages';
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof locale === 'undefined' || null === locale) {
 | 
			
		||||
        locale = getLocale();
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof message.translations === 'undefined') {
 | 
			
		||||
        return message.id;
 | 
			
		||||
    }
 | 
			
		||||
    const localesFallbacks = getLocaleFallbacks();
 | 
			
		||||
    const translationsIntl = message.translations[`${domain}+intl-icu`];
 | 
			
		||||
    if (typeof translationsIntl !== 'undefined') {
 | 
			
		||||
        while (typeof translationsIntl[locale] === 'undefined') {
 | 
			
		||||
            locale = localesFallbacks[locale];
 | 
			
		||||
            if (!locale) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (locale) {
 | 
			
		||||
            return formatIntl(translationsIntl[locale], parameters, locale);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    const translations = message.translations[domain];
 | 
			
		||||
    if (typeof translations !== 'undefined') {
 | 
			
		||||
        while (typeof translations[locale] === 'undefined') {
 | 
			
		||||
            locale = localesFallbacks[locale];
 | 
			
		||||
            if (!locale) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (locale) {
 | 
			
		||||
            return format(translations[locale], parameters, locale);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (_throwWhenNotFound) {
 | 
			
		||||
        throw new Error(`No translation message found with id "${message.id}".`);
 | 
			
		||||
    }
 | 
			
		||||
    return message.id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { getLocale, getLocaleFallbacks, setLocale, setLocaleFallbacks, throwWhenNotFound, trans };
 | 
			
		||||
							
								
								
									
										1
									
								
								assets/ux-translator/dist/utils.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/ux-translator/dist/utils.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export declare function strtr(string: string, replacePairs: Record<string, string | number>): string;
 | 
			
		||||
							
								
								
									
										34
									
								
								assets/ux-translator/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								assets/ux-translator/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@symfony/ux-translator",
 | 
			
		||||
    "description": "Symfony Translator for JavaScript",
 | 
			
		||||
    "license": "MIT",
 | 
			
		||||
    "version": "1.0.0",
 | 
			
		||||
    "main": "dist/translator_controller.js",
 | 
			
		||||
    "types": "dist/translator_controller.d.ts",
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "build": "node ../../../bin/build_package.js .",
 | 
			
		||||
        "watch": "node ../../../bin/build_package.js . --watch",
 | 
			
		||||
        "test": "../../../bin/test_package.sh .",
 | 
			
		||||
        "check": "biome check",
 | 
			
		||||
        "ci": "biome ci"
 | 
			
		||||
    },
 | 
			
		||||
    "symfony": {
 | 
			
		||||
        "importmap": {
 | 
			
		||||
            "intl-messageformat": "^10.5.11",
 | 
			
		||||
            "@symfony/ux-translator": "path:%PACKAGE%/dist/translator_controller.js",
 | 
			
		||||
            "@app/translations": "path:var/translations/index.js",
 | 
			
		||||
            "@app/translations/configuration": "path:var/translations/configuration.js"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "peerDependencies": {
 | 
			
		||||
        "intl-messageformat": "^10.5.11"
 | 
			
		||||
    },
 | 
			
		||||
    "peerDependenciesMeta": {
 | 
			
		||||
        "intl-messageformat": {
 | 
			
		||||
            "optional": false
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "intl-messageformat": "^10.5.11"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -75,6 +75,7 @@
 | 
			
		||||
        "symfony/templating": "^5.4",
 | 
			
		||||
        "symfony/translation": "^5.4",
 | 
			
		||||
        "symfony/twig-bundle": "^5.4",
 | 
			
		||||
        "symfony/ux-translator": "^2.22",
 | 
			
		||||
        "symfony/validator": "^5.4",
 | 
			
		||||
        "symfony/webpack-encore-bundle": "^1.11",
 | 
			
		||||
        "symfony/workflow": "^5.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -36,4 +36,5 @@ return [
 | 
			
		||||
    Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true],
 | 
			
		||||
    Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
 | 
			
		||||
    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
 | 
			
		||||
    Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
 | 
			
		||||
];
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								config/packages/ux_translator.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								config/packages/ux_translator.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
ux_translator:
 | 
			
		||||
    # The directory where the JavaScript translations are dumped
 | 
			
		||||
    dump_directory: '%kernel.project_dir%/var/translations'
 | 
			
		||||
@@ -220,6 +220,7 @@ framework:
 | 
			
		||||
                        - attenteModification
 | 
			
		||||
                        - attenteMiseEnForme
 | 
			
		||||
                        - attenteValidationMiseEnForme
 | 
			
		||||
                        - attenteSignature
 | 
			
		||||
                        - attenteVisa
 | 
			
		||||
                        - postSignature
 | 
			
		||||
                        - attenteTraitement
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,7 @@ We strongly encourage you to initialize a git repository at this step, to track
 | 
			
		||||
   # add the flex endpoints required for custom recipes
 | 
			
		||||
   cat <<< "$(jq '.extra.symfony += {"endpoint": ["flex://defaults", "https://gitlab.com/api/v4/projects/57371968/repository/files/index.json/raw?ref=main"]}' composer.json)" > composer.json
 | 
			
		||||
   # install chill and some dependencies
 | 
			
		||||
   # TODO fix the suffix "alpha1" and replace by ^3.0.0 when version 3.0.0 will be released
 | 
			
		||||
   symfony composer require chill-project/chill-bundles v3.0.0-RC3 champs-libres/wopi-lib dev-master@dev champs-libres/wopi-bundle dev-master@dev
 | 
			
		||||
   symfony composer require chill-project/chill-bundles ^3.7.1 champs-libres/wopi-lib dev-master@dev champs-libres/wopi-bundle dev-master@dev symfony/amqp-messenger
 | 
			
		||||
 | 
			
		||||
We encourage you to accept the inclusion of the "Docker configuration from recipes": this is the documented way to run the database.
 | 
			
		||||
You must also accept to configure recipes from the contrib repository, unless you want to configure the bundles manually).
 | 
			
		||||
@@ -48,7 +47,7 @@ You must also accept to configure recipes from the contrib repository, unless yo
 | 
			
		||||
 | 
			
		||||
   If you encounter this error during assets compilation (:code:`yarn run encore production`) (repeated multiple times):
 | 
			
		||||
 | 
			
		||||
   .. code-block:: txt
 | 
			
		||||
   .. code-block::
 | 
			
		||||
 | 
			
		||||
      [tsl] ERROR in /tmp/chill/v1/public/bundles/chillcalendar/types.ts(2,65)
 | 
			
		||||
            TS2307: Cannot find module '../../../ChillMainBundle/Resources/public/types' or its corresponding type declarations.
 | 
			
		||||
@@ -74,14 +73,22 @@ or in the :code:`.env.local` file, which should not be committed to the git repo
 | 
			
		||||
You do not need to set variables for the smtp server, redis server and relatorio server, as they are generated automatically
 | 
			
		||||
by the symfony server, from the docker compose services.
 | 
			
		||||
 | 
			
		||||
The only required variable is the :code:`ADMIN_PASSWORD`. You can generate a hashed and salted admin password using the command
 | 
			
		||||
:code:`symfony console security:hash-password <your password> 'Symfony\Component\Security\Core\User\User'`. Then,
 | 
			
		||||
The required variables are:
 | 
			
		||||
 | 
			
		||||
- the :code:`ADMIN_PASSWORD`;
 | 
			
		||||
- the :code:`OVHCLOUD_DSN` variable;
 | 
			
		||||
 | 
			
		||||
:code:`ADMIN_PASSWORD`
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
You can generate a hashed and salted admin password using the command
 | 
			
		||||
:code:`symfony console security:hash-password <your password> 'Symfony\Component\Security\Core\User\User'`.Then,
 | 
			
		||||
you can either:
 | 
			
		||||
 | 
			
		||||
- add this password to the :code:`.env.local` file, you must escape the character :code:`$`: if the generated password
 | 
			
		||||
  is :code:`$2y$13$iyvJLuT4YEa6iWXyQV4/N.hNHpNG8kXlYDkkt5MkYy4FXcSwYAwmm`, your :code:`.env.local` file will be:
 | 
			
		||||
 | 
			
		||||
  .. code-block:: env
 | 
			
		||||
  .. code-block:: bash
 | 
			
		||||
 | 
			
		||||
     ADMIN_PASSWORD=\$2y\$13\$iyvJLuT4YEa6iWXyQV4/N.hNHpNG8kXlYDkkt5MkYy4FXcSwYAwmm
 | 
			
		||||
     # note: if you copy-paste the line above, the password will be "admin".
 | 
			
		||||
@@ -89,12 +96,24 @@ you can either:
 | 
			
		||||
- add the generated password to the secrets manager (**note**: you must add the generated hashed password to the secrets env,
 | 
			
		||||
  not the password in clear text).
 | 
			
		||||
 | 
			
		||||
- set up the jwt authentication bundle
 | 
			
		||||
:code:`OVHCLOUD_DSN` and sending SMS messages
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
This is a temporary dependency, for ensuring compatibility for previous behaviour.
 | 
			
		||||
 | 
			
		||||
You can set it to :code:`null://null` if you do not plan to use sending SMS.
 | 
			
		||||
 | 
			
		||||
.. code-block:: bash
 | 
			
		||||
 | 
			
		||||
   OVHCLOUD_DSN=null://null
 | 
			
		||||
 | 
			
		||||
If you plan to do it, you can configure the notifier component `as described in the symfony documentation <https://symfony.com/doc/current/notifier.html#notifier-sms-channel>`_.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Some environment variables are available for the JWT authentication bundle in the :code:`.env` file.
 | 
			
		||||
 | 
			
		||||
Prepare migrations and other tools
 | 
			
		||||
----------------------------------
 | 
			
		||||
Prepare database, messenger queue, and other configuration
 | 
			
		||||
----------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
To continue the installation process, you will have to run migrations:
 | 
			
		||||
 | 
			
		||||
@@ -109,17 +128,22 @@ To continue the installation process, you will have to run migrations:
 | 
			
		||||
   symfony console messenger:setup-transports
 | 
			
		||||
   # prepare some views
 | 
			
		||||
   symfony console chill:db:sync-views
 | 
			
		||||
   # load languages data
 | 
			
		||||
   symfony console chill:main:languages:populate
 | 
			
		||||
   # generate jwt token, required for some api features (webdav access, ...)
 | 
			
		||||
   symfony console lexik:jwt:generate-keypair
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
   If you encounter an error while running :code:`symfony console messenger:setup-transports`, you can set up the messenger
 | 
			
		||||
   transport to redis, by adding this in the :code:`.env.local` or :code:`.env` file:
 | 
			
		||||
   If you encounter this error:
 | 
			
		||||
 | 
			
		||||
   .. code-block::
 | 
			
		||||
 | 
			
		||||
     No transport supports the given Messenger DSN.
 | 
			
		||||
 | 
			
		||||
   Please check that you installed the package `symfony/amqp-messenger`.
 | 
			
		||||
 | 
			
		||||
   .. code-block:: env
 | 
			
		||||
 | 
			
		||||
      MESSENGER_TRANSPORT_DSN=redis://${REDIS_HOST}:${REDIS_PORT}/messages
 | 
			
		||||
 | 
			
		||||
Start your web server locally
 | 
			
		||||
-----------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -41,16 +41,18 @@ Postal code are loaded from this database. There is no need to load postal codes
 | 
			
		||||
The data are prepared for Chill (`See this repository <https://gitea.champs-libres.be/Chill-project/belgian-bestaddresses-transform/releases>`_).
 | 
			
		||||
One can select postal code by his first number (:code:`1xxx` for postal codes from 1000 to 1999), or a limited list for development purpose.
 | 
			
		||||
 | 
			
		||||
The command expects a language code as first argument.
 | 
			
		||||
 | 
			
		||||
.. code-block:: bash
 | 
			
		||||
 | 
			
		||||
   # load postal code from 1000 to 3999:
 | 
			
		||||
   bin/console chill:main:address-ref-from-best-addresse 1xxx 2xxx 3xxx
 | 
			
		||||
   bin/console chill:main:address-ref-from-best-addresse fr 1xxx 2xxx 3xxx
 | 
			
		||||
 | 
			
		||||
   # load only an extract (for dev purposes)
 | 
			
		||||
   bin/console chill:main:address-ref-from-best-addresse extract
 | 
			
		||||
   bin/console chill:main:address-ref-from-best-addresse fr extract
 | 
			
		||||
 | 
			
		||||
   # load full addresses (discouraged)
 | 
			
		||||
   bin/console chill:main:address-ref-from-best-addresse full
 | 
			
		||||
   bin/console chill:main:address-ref-from-best-addresse fr full
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ export default ts.config(
 | 
			
		||||
            // override/add rules settings here, such as:
 | 
			
		||||
            "vue/multi-word-component-names": "off",
 | 
			
		||||
            "@typescript-eslint/no-require-imports": "off",
 | 
			
		||||
            "@typescript-eslint/ban-ts-comment": "off"
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								package.json
									
									
									
									
									
								
							@@ -6,15 +6,12 @@
 | 
			
		||||
    "@apidevtools/swagger-cli": "^4.0.4",
 | 
			
		||||
    "@babel/core": "^7.20.5",
 | 
			
		||||
    "@babel/preset-env": "^7.20.2",
 | 
			
		||||
    "@ckeditor/ckeditor5-build-classic": "^41.4.2",
 | 
			
		||||
    "@ckeditor/ckeditor5-dev-translations": "^40.2.0",
 | 
			
		||||
    "@ckeditor/ckeditor5-dev-utils": "^40.2.0",
 | 
			
		||||
    "@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13",
 | 
			
		||||
    "@ckeditor/ckeditor5-markdown-gfm": "^41.4.2",
 | 
			
		||||
    "@ckeditor/ckeditor5-theme-lark": "^41.4.2",
 | 
			
		||||
    "@ckeditor/ckeditor5-vue": "^5.1.0",
 | 
			
		||||
    "@ckeditor/ckeditor5-vue": "^7.3.0",
 | 
			
		||||
    "@eslint/js": "^9.14.0",
 | 
			
		||||
    "@hotwired/stimulus": "^3.0.0",
 | 
			
		||||
    "@luminateone/eslint-baseline": "^1.0.9",
 | 
			
		||||
    "@symfony/stimulus-bridge": "^3.2.0",
 | 
			
		||||
    "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets",
 | 
			
		||||
    "@symfony/webpack-encore": "^4.1.0",
 | 
			
		||||
    "@tsconfig/node20": "^20.1.4",
 | 
			
		||||
    "@types/dompurify": "^3.0.5",
 | 
			
		||||
@@ -23,12 +20,14 @@
 | 
			
		||||
    "bindings": "^1.5.0",
 | 
			
		||||
    "bootstrap": "5.2.3",
 | 
			
		||||
    "chokidar": "^3.5.1",
 | 
			
		||||
    "ckeditor5": "^44.1.0",
 | 
			
		||||
    "dompurify": "^3.1.0",
 | 
			
		||||
    "eslint": "^9.14.0",
 | 
			
		||||
    "eslint-config-prettier": "^9.1.0",
 | 
			
		||||
    "eslint-plugin-prettier": "^5.2.1",
 | 
			
		||||
    "eslint-plugin-vue": "^9.30.0",
 | 
			
		||||
    "fork-awesome": "^1.1.7",
 | 
			
		||||
    "intl-messageformat": "^10.5.11",
 | 
			
		||||
    "jquery": "^3.6.0",
 | 
			
		||||
    "node-sass": "^8.0.0",
 | 
			
		||||
    "popper.js": "^1.16.1",
 | 
			
		||||
@@ -54,11 +53,13 @@
 | 
			
		||||
    "@fullcalendar/timegrid": "^6.1.4",
 | 
			
		||||
    "@fullcalendar/vue3": "^6.1.4",
 | 
			
		||||
    "@popperjs/core": "^2.9.2",
 | 
			
		||||
    "@tsconfig/node20": "^20.1.4",
 | 
			
		||||
    "@types/dompurify": "^3.0.5",
 | 
			
		||||
    "@types/leaflet": "^1.9.3",
 | 
			
		||||
    "bootstrap-icons": "^1.11.3",
 | 
			
		||||
    "dropzone": "^5.7.6",
 | 
			
		||||
    "es6-promise": "^4.2.8",
 | 
			
		||||
    "intl-messageformat": "^10.5.11",
 | 
			
		||||
    "leaflet": "^1.7.1",
 | 
			
		||||
    "marked": "^12.0.2",
 | 
			
		||||
    "masonry-layout": "^4.2.2",
 | 
			
		||||
@@ -72,7 +73,7 @@
 | 
			
		||||
    "vuex": "^4.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "browserslist": [
 | 
			
		||||
    "Firefox ESR"
 | 
			
		||||
    "defaults and fully supports es6-module and not dead"
 | 
			
		||||
  ],
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev-server": "encore dev-server",
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\ActivityBundle\Menu;
 | 
			
		||||
 | 
			
		||||
use Chill\ActivityBundle\Entity\Activity;
 | 
			
		||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
 | 
			
		||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
 | 
			
		||||
@@ -23,22 +24,30 @@ use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 */
 | 
			
		||||
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(protected Security $security, protected TranslatorInterface $translator) {}
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        protected Security $security,
 | 
			
		||||
        protected TranslatorInterface $translator,
 | 
			
		||||
        private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function buildMenu($menuId, MenuItem $menu, array $parameters)
 | 
			
		||||
    {
 | 
			
		||||
        $period = $parameters['accompanyingCourse'];
 | 
			
		||||
 | 
			
		||||
        $activities = $this->managerRegistry->getManager()->getRepository(Activity::class)->findBy(
 | 
			
		||||
            ['accompanyingPeriod' => $period]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
            AccompanyingPeriod::STEP_DRAFT !== $period->getStep()
 | 
			
		||||
            && $this->security->isGranted(ActivityVoter::SEE, $period)
 | 
			
		||||
        ) {
 | 
			
		||||
            $menu->addChild($this->translator->trans('Activity'), [
 | 
			
		||||
            $menu->addChild($this->translator->trans('Activities'), [
 | 
			
		||||
                'route' => 'chill_activity_activity_list',
 | 
			
		||||
                'routeParameters' => [
 | 
			
		||||
                    'accompanying_period_id' => $period->getId(),
 | 
			
		||||
                ], ])
 | 
			
		||||
                ->setExtras(['order' => 40]);
 | 
			
		||||
                ->setExtras(['order' => 40, 'counter' => count($activities) > 0 ? count($activities) : null]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\ActivityBundle\Menu;
 | 
			
		||||
 | 
			
		||||
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
 | 
			
		||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
 | 
			
		||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
@@ -23,13 +24,20 @@ use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 */
 | 
			
		||||
final readonly class PersonMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(private AuthorizationCheckerInterface $authorizationChecker, private TranslatorInterface $translator) {}
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private readonly ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
 | 
			
		||||
        private AuthorizationCheckerInterface $authorizationChecker,
 | 
			
		||||
        private TranslatorInterface $translator,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function buildMenu($menuId, MenuItem $menu, array $parameters)
 | 
			
		||||
    {
 | 
			
		||||
        /** @var Person $person */
 | 
			
		||||
        $person = $parameters['person'];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $count = $this->activityACLAwareRepository->countByPerson($person, ActivityVoter::SEE);
 | 
			
		||||
 | 
			
		||||
        if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
 | 
			
		||||
            $menu->addChild(
 | 
			
		||||
                $this->translator->trans('Activities'),
 | 
			
		||||
@@ -38,7 +46,7 @@ final readonly class PersonMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
                    'routeParameters' => ['person_id' => $person->getId()],
 | 
			
		||||
                ]
 | 
			
		||||
            )
 | 
			
		||||
                ->setExtra('order', 201);
 | 
			
		||||
                ->setExtras(['order' => 201, 'counter' => $count > 0 ? $count : null]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -120,3 +120,34 @@ li.document-list-item {
 | 
			
		||||
        vertical-align: baseline;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.badge-activity-type-simple {
 | 
			
		||||
    @extend .badge;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    margin: 0.2rem 0;
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
    padding-right: 0.5rem;
 | 
			
		||||
 | 
			
		||||
    border-left: 20px groove #9acd32;
 | 
			
		||||
    border-radius: $badge-border-radius;
 | 
			
		||||
 | 
			
		||||
    color: black;
 | 
			
		||||
    font-weight: normal;
 | 
			
		||||
    font-size: unset;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
    background-color: $gray-100;
 | 
			
		||||
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    text-indent: 5px hanging;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
 | 
			
		||||
    &::before {
 | 
			
		||||
        margin-right: 3px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        left: -0.5px;
 | 
			
		||||
        font-family: ForkAwesome;
 | 
			
		||||
        content: '\f04b';
 | 
			
		||||
        color: #9acd32;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import Location from "./components/Location.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "App",
 | 
			
		||||
    props: ["hasSocialIssues", "hasLocation", "hasPerson"],
 | 
			
		||||
    props: ["hasSocialIssues", "hasLocation", "hasPerson", "isSimpleEditor"],
 | 
			
		||||
    components: {
 | 
			
		||||
        ConcernedGroups,
 | 
			
		||||
        SocialIssuesAcc,
 | 
			
		||||
 
 | 
			
		||||
@@ -30,13 +30,14 @@
 | 
			
		||||
        <ul class="record_actions">
 | 
			
		||||
            <li class="add-persons">
 | 
			
		||||
                <add-persons
 | 
			
		||||
                    button-title="activity.add_persons"
 | 
			
		||||
                    modal-title="activity.add_persons"
 | 
			
		||||
                    :key="addPersons.key"
 | 
			
		||||
                    :options="addPersonsOptions"
 | 
			
		||||
                    @add-new-persons="addNewPersons"
 | 
			
		||||
                    :buttonTitle="trans(ACTIVITY_ADD_PERSONS)"
 | 
			
		||||
                    :modalTitle="trans(ACTIVITY_ADD_PERSONS)"
 | 
			
		||||
                    v-bind:key="addPersons.key"
 | 
			
		||||
                    v-bind:options="addPersonsOptions"
 | 
			
		||||
                    @addNewPersons="addNewPersons"
 | 
			
		||||
                    ref="addPersons"
 | 
			
		||||
                />
 | 
			
		||||
                >
 | 
			
		||||
                </add-persons>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </teleport>
 | 
			
		||||
@@ -47,6 +48,14 @@ import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
 | 
			
		||||
import PersonsBloc from "./ConcernedGroups/PersonsBloc.vue";
 | 
			
		||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
 | 
			
		||||
import {
 | 
			
		||||
    ACTIVITY_BLOC_PERSONS,
 | 
			
		||||
    ACTIVITY_BLOC_PERSONS_ASSOCIATED,
 | 
			
		||||
    ACTIVITY_BLOC_THIRDPARTY,
 | 
			
		||||
    ACTIVITY_BLOC_USERS,
 | 
			
		||||
    ACTIVITY_ADD_PERSONS,
 | 
			
		||||
    trans,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "ConcernedGroups",
 | 
			
		||||
@@ -55,18 +64,24 @@ export default {
 | 
			
		||||
        PersonsBloc,
 | 
			
		||||
        PersonText,
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
        return {
 | 
			
		||||
            trans,
 | 
			
		||||
            ACTIVITY_ADD_PERSONS,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            personsBlocs: [
 | 
			
		||||
                {
 | 
			
		||||
                    key: "persons",
 | 
			
		||||
                    title: "activity.bloc_persons",
 | 
			
		||||
                    title: trans(ACTIVITY_BLOC_PERSONS),
 | 
			
		||||
                    persons: [],
 | 
			
		||||
                    included: false,
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    key: "personsAssociated",
 | 
			
		||||
                    title: "activity.bloc_persons_associated",
 | 
			
		||||
                    title: trans(ACTIVITY_BLOC_PERSONS_ASSOCIATED),
 | 
			
		||||
                    persons: [],
 | 
			
		||||
                    included: window.activity
 | 
			
		||||
                        ? window.activity.activityType.personsVisible !== 0
 | 
			
		||||
@@ -82,7 +97,7 @@ export default {
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    key: "thirdparty",
 | 
			
		||||
                    title: "activity.bloc_thirdparty",
 | 
			
		||||
                    title: trans(ACTIVITY_BLOC_THIRDPARTY),
 | 
			
		||||
                    persons: [],
 | 
			
		||||
                    included: window.activity
 | 
			
		||||
                        ? window.activity.activityType.thirdPartiesVisible !== 0
 | 
			
		||||
@@ -90,7 +105,7 @@ export default {
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    key: "users",
 | 
			
		||||
                    title: "activity.bloc_users",
 | 
			
		||||
                    title: trans(ACTIVITY_BLOC_USERS),
 | 
			
		||||
                    persons: [],
 | 
			
		||||
                    included: window.activity
 | 
			
		||||
                        ? window.activity.activityType.usersVisible !== 0
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
    <teleport to="#location">
 | 
			
		||||
        <div class="mb-3 row">
 | 
			
		||||
            <label :class="locationClassList">
 | 
			
		||||
                {{ $t("activity.location") }}
 | 
			
		||||
                {{ trans(ACTIVITY_LOCATION) }}
 | 
			
		||||
            </label>
 | 
			
		||||
            <div class="col-sm-8">
 | 
			
		||||
                <VueMultiselect
 | 
			
		||||
@@ -13,17 +13,17 @@
 | 
			
		||||
                    open-direction="top"
 | 
			
		||||
                    :multiple="false"
 | 
			
		||||
                    :searchable="true"
 | 
			
		||||
                    :placeholder="$t('activity.choose_location')"
 | 
			
		||||
                    :placeholder="trans(ACTIVITY_CHOOSE_LOCATION)"
 | 
			
		||||
                    :custom-label="customLabel"
 | 
			
		||||
                    :select-label="$t('multiselect.select_label')"
 | 
			
		||||
                    :deselect-label="$t('multiselect.deselect_label')"
 | 
			
		||||
                    :selected-label="$t('multiselect.selected_label')"
 | 
			
		||||
                    :select-label="trans(MULTISELECT_SELECT_LABEL)"
 | 
			
		||||
                    :deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
 | 
			
		||||
                    :selected-label="trans(MULTISELECT_SELECTED_LABEL)"
 | 
			
		||||
                    :options="availableLocations"
 | 
			
		||||
                    group-values="locations"
 | 
			
		||||
                    group-label="locationGroup"
 | 
			
		||||
                    v-model="location"
 | 
			
		||||
                />
 | 
			
		||||
                <new-location :available-locations="availableLocations" />
 | 
			
		||||
                <new-location v-bind:available-locations="availableLocations" />
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </teleport>
 | 
			
		||||
@@ -33,6 +33,14 @@
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import VueMultiselect from "vue-multiselect";
 | 
			
		||||
import NewLocation from "./Location/NewLocation.vue";
 | 
			
		||||
import {
 | 
			
		||||
    trans,
 | 
			
		||||
    ACTIVITY_LOCATION,
 | 
			
		||||
    ACTIVITY_CHOOSE_LOCATION,
 | 
			
		||||
    MULTISELECT_SELECT_LABEL,
 | 
			
		||||
    MULTISELECT_DESELECT_LABEL,
 | 
			
		||||
    MULTISELECT_SELECTED_LABEL,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "Location",
 | 
			
		||||
@@ -40,6 +48,16 @@ export default {
 | 
			
		||||
        NewLocation,
 | 
			
		||||
        VueMultiselect,
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
        return {
 | 
			
		||||
            trans,
 | 
			
		||||
            ACTIVITY_LOCATION,
 | 
			
		||||
            ACTIVITY_CHOOSE_LOCATION,
 | 
			
		||||
            MULTISELECT_SELECT_LABEL,
 | 
			
		||||
            MULTISELECT_DESELECT_LABEL,
 | 
			
		||||
            MULTISELECT_SELECTED_LABEL,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            locationClassList: `col-form-label col-sm-4 ${document.querySelector("input#chill_activitybundle_activity_location").getAttribute("required") ? "required" : ""}`,
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
        <ul class="record_actions">
 | 
			
		||||
            <li>
 | 
			
		||||
                <a class="btn btn-sm btn-create" @click="openModal">
 | 
			
		||||
                    {{ $t("activity.create_new_location") }}
 | 
			
		||||
                    {{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
 | 
			
		||||
                </a>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
@@ -11,12 +11,12 @@
 | 
			
		||||
        <teleport to="body">
 | 
			
		||||
            <modal
 | 
			
		||||
                v-if="modal.showModal"
 | 
			
		||||
                :modal-dialog-class="modal.modalDialogClass"
 | 
			
		||||
                :modalDialogClass="modal.modalDialogClass"
 | 
			
		||||
                @close="modal.showModal = false"
 | 
			
		||||
            >
 | 
			
		||||
                <template #header>
 | 
			
		||||
                    <h3 class="modal-title">
 | 
			
		||||
                        {{ $t("activity.create_new_location") }}
 | 
			
		||||
                        {{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
 | 
			
		||||
                    </h3>
 | 
			
		||||
                </template>
 | 
			
		||||
                <template #body>
 | 
			
		||||
@@ -37,7 +37,7 @@
 | 
			
		||||
                                v-model="selectType"
 | 
			
		||||
                            >
 | 
			
		||||
                                <option selected disabled value="">
 | 
			
		||||
                                    {{ $t("activity.choose_location_type") }}
 | 
			
		||||
                                    {{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
 | 
			
		||||
                                </option>
 | 
			
		||||
                                <option
 | 
			
		||||
                                    v-for="t in locationTypes"
 | 
			
		||||
@@ -48,7 +48,7 @@
 | 
			
		||||
                                </option>
 | 
			
		||||
                            </select>
 | 
			
		||||
                            <label>{{
 | 
			
		||||
                                $t("activity.location_fields.type")
 | 
			
		||||
                                trans(ACTIVITY_LOCATION_FIELDS_TYPE)
 | 
			
		||||
                            }}</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
@@ -60,14 +60,14 @@
 | 
			
		||||
                                placeholder
 | 
			
		||||
                            />
 | 
			
		||||
                            <label for="name">{{
 | 
			
		||||
                                $t("activity.location_fields.name")
 | 
			
		||||
                                trans(ACTIVITY_LOCATION_FIELDS_NAME)
 | 
			
		||||
                            }}</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <add-address
 | 
			
		||||
                            :context="addAddress.context"
 | 
			
		||||
                            :options="addAddress.options"
 | 
			
		||||
                            :address-changed-callback="submitNewAddress"
 | 
			
		||||
                            :addressChangedCallback="submitNewAddress"
 | 
			
		||||
                            v-if="showAddAddress"
 | 
			
		||||
                            ref="addAddress"
 | 
			
		||||
                        />
 | 
			
		||||
@@ -80,7 +80,7 @@
 | 
			
		||||
                                placeholder
 | 
			
		||||
                            />
 | 
			
		||||
                            <label for="phonenumber1">{{
 | 
			
		||||
                                $t("activity.location_fields.phonenumber1")
 | 
			
		||||
                                trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER1)
 | 
			
		||||
                            }}</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="form-floating mb-3" v-if="hasPhonenumber1">
 | 
			
		||||
@@ -91,7 +91,7 @@
 | 
			
		||||
                                placeholder
 | 
			
		||||
                            />
 | 
			
		||||
                            <label for="phonenumber2">{{
 | 
			
		||||
                                $t("activity.location_fields.phonenumber2")
 | 
			
		||||
                                trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER2)
 | 
			
		||||
                            }}</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="form-floating mb-3" v-if="showContactData">
 | 
			
		||||
@@ -102,7 +102,7 @@
 | 
			
		||||
                                placeholder
 | 
			
		||||
                            />
 | 
			
		||||
                            <label for="email">{{
 | 
			
		||||
                                $t("activity.location_fields.email")
 | 
			
		||||
                                trans(ACTIVITY_LOCATION_FIELDS_EMAIL)
 | 
			
		||||
                            }}</label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
@@ -112,7 +112,7 @@
 | 
			
		||||
                        class="btn btn-save"
 | 
			
		||||
                        @click.prevent="saveNewLocation"
 | 
			
		||||
                    >
 | 
			
		||||
                        {{ $t("action.save") }}
 | 
			
		||||
                        {{ trans(SAVE) }}
 | 
			
		||||
                    </button>
 | 
			
		||||
                </template>
 | 
			
		||||
            </modal>
 | 
			
		||||
@@ -126,6 +126,17 @@ import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue"
 | 
			
		||||
import { mapState } from "vuex";
 | 
			
		||||
import { getLocationTypes } from "../../api";
 | 
			
		||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
 | 
			
		||||
import {
 | 
			
		||||
    SAVE,
 | 
			
		||||
    ACTIVITY_LOCATION_FIELDS_EMAIL,
 | 
			
		||||
    ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
 | 
			
		||||
    ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
 | 
			
		||||
    ACTIVITY_LOCATION_FIELDS_NAME,
 | 
			
		||||
    ACTIVITY_LOCATION_FIELDS_TYPE,
 | 
			
		||||
    ACTIVITY_CHOOSE_LOCATION_TYPE,
 | 
			
		||||
    ACTIVITY_CREATE_NEW_LOCATION,
 | 
			
		||||
    trans,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "NewLocation",
 | 
			
		||||
@@ -133,6 +144,19 @@ export default {
 | 
			
		||||
        Modal,
 | 
			
		||||
        AddAddress,
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
        return {
 | 
			
		||||
            trans,
 | 
			
		||||
            SAVE,
 | 
			
		||||
            ACTIVITY_LOCATION_FIELDS_EMAIL,
 | 
			
		||||
            ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
 | 
			
		||||
            ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
 | 
			
		||||
            ACTIVITY_LOCATION_FIELDS_NAME,
 | 
			
		||||
            ACTIVITY_LOCATION_FIELDS_TYPE,
 | 
			
		||||
            ACTIVITY_CHOOSE_LOCATION_TYPE,
 | 
			
		||||
            ACTIVITY_CREATE_NEW_LOCATION,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    props: ["availableLocations"],
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
        <div class="mb-3 row">
 | 
			
		||||
            <div class="col-4">
 | 
			
		||||
                <label :class="socialIssuesClassList">{{
 | 
			
		||||
                    $t("activity.social_issues")
 | 
			
		||||
                    trans(ACTIVITY_SOCIAL_ISSUES)
 | 
			
		||||
                }}</label>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-8">
 | 
			
		||||
@@ -12,8 +12,9 @@
 | 
			
		||||
                    :key="issue.id"
 | 
			
		||||
                    :issue="issue"
 | 
			
		||||
                    :selection="socialIssuesSelected"
 | 
			
		||||
                    @update-selected="updateIssuesSelected"
 | 
			
		||||
                />
 | 
			
		||||
                    @updateSelected="updateIssuesSelected"
 | 
			
		||||
                >
 | 
			
		||||
                </check-social-issue>
 | 
			
		||||
 | 
			
		||||
                <div class="my-3">
 | 
			
		||||
                    <VueMultiselect
 | 
			
		||||
@@ -31,10 +32,11 @@
 | 
			
		||||
                        :allow-empty="true"
 | 
			
		||||
                        :show-labels="false"
 | 
			
		||||
                        :loading="issueIsLoading"
 | 
			
		||||
                        :placeholder="$t('activity.choose_other_social_issue')"
 | 
			
		||||
                        :placeholder="trans(ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE)"
 | 
			
		||||
                        :options="socialIssuesOther"
 | 
			
		||||
                        @select="addIssueInList"
 | 
			
		||||
                    />
 | 
			
		||||
                    >
 | 
			
		||||
                    </VueMultiselect>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -42,35 +44,46 @@
 | 
			
		||||
        <div class="mb-3 row">
 | 
			
		||||
            <div class="col-4">
 | 
			
		||||
                <label :class="socialActionsClassList">{{
 | 
			
		||||
                    $t("activity.social_actions")
 | 
			
		||||
                    trans(ACTIVITY_SOCIAL_ACTIONS)
 | 
			
		||||
                }}</label>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-8">
 | 
			
		||||
                <div v-if="actionIsLoading === true">
 | 
			
		||||
                    <i class="chill-green fa fa-circle-o-notch fa-spin fa-lg" />
 | 
			
		||||
                    <i
 | 
			
		||||
                        class="chill-green fa fa-circle-o-notch fa-spin fa-lg"
 | 
			
		||||
                    ></i>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <span
 | 
			
		||||
                    v-else-if="socialIssuesSelected.length === 0"
 | 
			
		||||
                    class="inline-choice chill-no-data-statement mt-3"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("activity.select_first_a_social_issue") }}
 | 
			
		||||
                    {{ trans(ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE) }}
 | 
			
		||||
                </span>
 | 
			
		||||
 | 
			
		||||
                <template v-else-if="socialActionsList.length > 0">
 | 
			
		||||
                <template
 | 
			
		||||
                    v-else-if="
 | 
			
		||||
                        socialActionsList.length > 0 &&
 | 
			
		||||
                        (socialIssuesSelected.length ||
 | 
			
		||||
                            socialActionsSelected.length)
 | 
			
		||||
                    "
 | 
			
		||||
                >
 | 
			
		||||
                    <div
 | 
			
		||||
                        v-if="
 | 
			
		||||
                            socialIssuesSelected.length ||
 | 
			
		||||
                            socialActionsSelected.length
 | 
			
		||||
                        "
 | 
			
		||||
                        id="actionsList"
 | 
			
		||||
                        v-for="group in socialActionsList"
 | 
			
		||||
                        :key="group.issue"
 | 
			
		||||
                    >
 | 
			
		||||
                        <span class="badge bg-chill-l-gray text-dark">{{
 | 
			
		||||
                            group.issue
 | 
			
		||||
                        }}</span>
 | 
			
		||||
                        <check-social-action
 | 
			
		||||
                            v-for="action in socialActionsList"
 | 
			
		||||
                            v-for="action in group.actions"
 | 
			
		||||
                            :key="action.id"
 | 
			
		||||
                            :action="action"
 | 
			
		||||
                            :selection="socialActionsSelected"
 | 
			
		||||
                            @update-selected="updateActionsSelected"
 | 
			
		||||
                        />
 | 
			
		||||
                            @updateSelected="updateActionsSelected"
 | 
			
		||||
                        >
 | 
			
		||||
                        </check-social-action>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +93,7 @@
 | 
			
		||||
                    "
 | 
			
		||||
                    class="inline-choice chill-no-data-statement mt-3"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("activity.social_action_list_empty") }}
 | 
			
		||||
                    {{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -92,6 +105,14 @@ import VueMultiselect from "vue-multiselect";
 | 
			
		||||
import CheckSocialIssue from "./SocialIssuesAcc/CheckSocialIssue.vue";
 | 
			
		||||
import CheckSocialAction from "./SocialIssuesAcc/CheckSocialAction.vue";
 | 
			
		||||
import { getSocialIssues, getSocialActionByIssue } from "../api.js";
 | 
			
		||||
import {
 | 
			
		||||
    ACTIVITY_SOCIAL_ACTION_LIST_EMPTY,
 | 
			
		||||
    ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE,
 | 
			
		||||
    ACTIVITY_SOCIAL_ACTIONS,
 | 
			
		||||
    ACTIVITY_SOCIAL_ISSUES,
 | 
			
		||||
    ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE,
 | 
			
		||||
    trans,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "SocialIssuesAcc",
 | 
			
		||||
@@ -100,6 +121,16 @@ export default {
 | 
			
		||||
        CheckSocialAction,
 | 
			
		||||
        VueMultiselect,
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
        return {
 | 
			
		||||
            trans,
 | 
			
		||||
            ACTIVITY_SOCIAL_ACTION_LIST_EMPTY,
 | 
			
		||||
            ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE,
 | 
			
		||||
            ACTIVITY_SOCIAL_ACTIONS,
 | 
			
		||||
            ACTIVITY_SOCIAL_ISSUES,
 | 
			
		||||
            ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            issueIsLoading: false,
 | 
			
		||||
@@ -127,53 +158,44 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        /* Load others issues in multiselect
 | 
			
		||||
         */
 | 
			
		||||
        /* Load other issues in multiselect */
 | 
			
		||||
        this.issueIsLoading = true;
 | 
			
		||||
        this.actionAreLoaded = false;
 | 
			
		||||
        getSocialIssues().then(
 | 
			
		||||
            (response) =>
 | 
			
		||||
                new Promise((resolve, reject) => {
 | 
			
		||||
                    this.$store.commit("updateIssuesOther", response.results);
 | 
			
		||||
 | 
			
		||||
                    /* Add in list the issues already associated (if not yet listed)
 | 
			
		||||
                     */
 | 
			
		||||
                    this.socialIssuesSelected.forEach((issue) => {
 | 
			
		||||
                        if (
 | 
			
		||||
                            this.socialIssuesList.filter(
 | 
			
		||||
                                (i) => i.id === issue.id,
 | 
			
		||||
                            ).length !== 1
 | 
			
		||||
                        ) {
 | 
			
		||||
                            this.$store.commit("addIssueInList", issue);
 | 
			
		||||
                        }
 | 
			
		||||
                    }, this);
 | 
			
		||||
        getSocialIssues().then((response) => {
 | 
			
		||||
            /* Add issues to the store */
 | 
			
		||||
            this.$store.commit("updateIssuesOther", response);
 | 
			
		||||
 | 
			
		||||
                    /* Remove from multiselect the issues that are not yet in checkbox list
 | 
			
		||||
                     */
 | 
			
		||||
                    this.socialIssuesList.forEach((issue) => {
 | 
			
		||||
                        this.$store.commit("removeIssueInOther", issue);
 | 
			
		||||
                    }, this);
 | 
			
		||||
            /* Add in list the issues already associated (if not yet listed) */
 | 
			
		||||
            this.socialIssuesSelected.forEach((issue) => {
 | 
			
		||||
                if (
 | 
			
		||||
                    this.socialIssuesList.filter((i) => i.id === issue.id)
 | 
			
		||||
                        .length !== 1
 | 
			
		||||
                ) {
 | 
			
		||||
                    this.$store.commit("addIssueInList", issue);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                    /* Filter issues
 | 
			
		||||
                     */
 | 
			
		||||
                    this.$store.commit("filterList", "issues");
 | 
			
		||||
            /* Remove from multiselect the issues that are not yet in the checkbox list */
 | 
			
		||||
            this.socialIssuesList.forEach((issue) => {
 | 
			
		||||
                this.$store.commit("removeIssueInOther", issue);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                    /* Add in list the actions already associated (if not yet listed)
 | 
			
		||||
                     */
 | 
			
		||||
                    this.socialActionsSelected.forEach((action) => {
 | 
			
		||||
                        this.$store.commit("addActionInList", action);
 | 
			
		||||
                    }, this);
 | 
			
		||||
            /* Filter issues */
 | 
			
		||||
            this.$store.commit("filterList", "issues");
 | 
			
		||||
 | 
			
		||||
                    /* Filter issues
 | 
			
		||||
                     */
 | 
			
		||||
                    this.$store.commit("filterList", "actions");
 | 
			
		||||
            /* Add in list the actions already associated (if not yet listed) */
 | 
			
		||||
            this.socialActionsSelected.forEach((action) => {
 | 
			
		||||
                this.$store.commit("addActionInList", action);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                    this.issueIsLoading = false;
 | 
			
		||||
                    this.actionAreLoaded = true;
 | 
			
		||||
                    this.updateActionsList();
 | 
			
		||||
                    resolve();
 | 
			
		||||
                }),
 | 
			
		||||
        );
 | 
			
		||||
            /* Filter actions */
 | 
			
		||||
            this.$store.commit("filterList", "actions");
 | 
			
		||||
 | 
			
		||||
            this.issueIsLoading = false;
 | 
			
		||||
            this.actionAreLoaded = true;
 | 
			
		||||
            this.updateActionsList();
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        /* When choosing an issue in multiselect, add it in checkboxes (as selected),
 | 
			
		||||
@@ -208,7 +230,7 @@ export default {
 | 
			
		||||
                this.actionIsLoading = true;
 | 
			
		||||
                getSocialActionByIssue(item.id).then(
 | 
			
		||||
                    (actions) =>
 | 
			
		||||
                        new Promise((resolve, reject) => {
 | 
			
		||||
                        new Promise((resolve) => {
 | 
			
		||||
                            actions.results.forEach((action) => {
 | 
			
		||||
                                this.$store.commit("addActionInList", action);
 | 
			
		||||
                            }, this);
 | 
			
		||||
@@ -235,9 +257,24 @@ export default {
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
@import "ChillMainAssets/module/bootstrap/shared";
 | 
			
		||||
@import "ChillPersonAssets/chill/scss/mixins";
 | 
			
		||||
@import "ChillMainAssets/chill/scss/chill_variables";
 | 
			
		||||
 | 
			
		||||
span.multiselect__single {
 | 
			
		||||
    display: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#actionsList {
 | 
			
		||||
    border-radius: 0.5rem;
 | 
			
		||||
    padding: 1rem;
 | 
			
		||||
    margin: 0.5rem;
 | 
			
		||||
    background-color: whitesmoke;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.badge {
 | 
			
		||||
    margin-bottom: 0.5rem;
 | 
			
		||||
    @include badge_social($social-issue-color);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,9 @@
 | 
			
		||||
                :value="action"
 | 
			
		||||
            />
 | 
			
		||||
            <label class="form-check-label" :for="action.id">
 | 
			
		||||
                <span class="badge bg-light text-dark">{{ action.text }}</span>
 | 
			
		||||
                <span class="badge bg-light text-dark" :title="action.text">{{
 | 
			
		||||
                    action.text
 | 
			
		||||
                }}</span>
 | 
			
		||||
            </label>
 | 
			
		||||
        </div>
 | 
			
		||||
    </span>
 | 
			
		||||
@@ -43,5 +45,9 @@ span.badge {
 | 
			
		||||
    font-size: 95%;
 | 
			
		||||
    margin-bottom: 5px;
 | 
			
		||||
    margin-right: 1em;
 | 
			
		||||
    max-width: 100%; /* Adjust as needed */
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,18 +14,21 @@ const i18n = _createI18n(activityMessages);
 | 
			
		||||
const hasSocialIssues = document.querySelector("#social-issues-acc") !== null;
 | 
			
		||||
const hasLocation = document.querySelector("#location") !== null;
 | 
			
		||||
const hasPerson = document.querySelector("#add-persons") !== null;
 | 
			
		||||
const isSimpleEditor = true;
 | 
			
		||||
 | 
			
		||||
const app = createApp({
 | 
			
		||||
  template: `<app
 | 
			
		||||
       :hasSocialIssues="hasSocialIssues"
 | 
			
		||||
       :hasLocation="hasLocation"
 | 
			
		||||
       :hasPerson="hasPerson"
 | 
			
		||||
       :isSimpleEditor = "isSimpleEditor"
 | 
			
		||||
    ></app>`,
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      hasSocialIssues,
 | 
			
		||||
      hasLocation,
 | 
			
		||||
      hasPerson,
 | 
			
		||||
      isSimpleEditor
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ const store = createStore({
 | 
			
		||||
  state: {
 | 
			
		||||
    me: null,
 | 
			
		||||
    activity: window.activity,
 | 
			
		||||
    accompanyingPeriodWorks: [],
 | 
			
		||||
    socialIssuesOther: [],
 | 
			
		||||
    socialActionsList: [],
 | 
			
		||||
    availableLocations: [],
 | 
			
		||||
@@ -41,7 +42,7 @@ const store = createStore({
 | 
			
		||||
      const allEntities = [
 | 
			
		||||
        ...store.getters.suggestedPersons,
 | 
			
		||||
        ...store.getters.suggestedRequestor,
 | 
			
		||||
        ...store.getters.suggestedUser,
 | 
			
		||||
        ...store.getters.suggestedUsers,
 | 
			
		||||
        ...store.getters.suggestedResources,
 | 
			
		||||
      ];
 | 
			
		||||
      const uniqueIds = [
 | 
			
		||||
@@ -80,8 +81,7 @@ const store = createStore({
 | 
			
		||||
            state.activity.activityType.thirdPartiesVisible !== 0),
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    suggestedUser(state) {
 | 
			
		||||
      // console.log('current user', state.me)
 | 
			
		||||
    suggestedUsers(state) {
 | 
			
		||||
      const existingUserIds = state.activity.users.map((p) => p.id);
 | 
			
		||||
      let suggestedUsers =
 | 
			
		||||
        state.activity.activityType.usersVisible === 0
 | 
			
		||||
@@ -90,11 +90,18 @@ const store = createStore({
 | 
			
		||||
              (u) => u !== null && !existingUserIds.includes(u.id),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
      state.accompanyingPeriodWorks.forEach((work) => {
 | 
			
		||||
        work.referrers.forEach((r) => {
 | 
			
		||||
          if (!existingUserIds.includes(r.id)) {
 | 
			
		||||
            suggestedUsers.push(r);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      // Add the current user from the state
 | 
			
		||||
      if (state.me && !existingUserIds.includes(state.me.id)) {
 | 
			
		||||
        suggestedUsers.push(state.me);
 | 
			
		||||
      }
 | 
			
		||||
      console.log("suggested users", suggestedUsers);
 | 
			
		||||
      // console.log("suggested users", suggestedUsers);
 | 
			
		||||
 | 
			
		||||
      return suggestedUsers;
 | 
			
		||||
    },
 | 
			
		||||
@@ -117,9 +124,19 @@ const store = createStore({
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
    socialActionsListSorted(state) {
 | 
			
		||||
      return [...state.socialActionsList].sort(
 | 
			
		||||
        (a, b) => a.ordering - b.ordering,
 | 
			
		||||
      );
 | 
			
		||||
      return [...state.socialActionsList]
 | 
			
		||||
        .sort((a, b) => a.ordering - b.ordering)
 | 
			
		||||
        .reduce((acc, action) => {
 | 
			
		||||
          const issueText = action.issue?.text || "Uncategorized";
 | 
			
		||||
          // Find if the group for the issue already exists
 | 
			
		||||
          let group = acc.find((item) => item.issue === issueText);
 | 
			
		||||
          if (!group) {
 | 
			
		||||
            group = { issue: issueText, actions: [] };
 | 
			
		||||
            acc.push(group);
 | 
			
		||||
          }
 | 
			
		||||
          group.actions.push(action);
 | 
			
		||||
          return acc;
 | 
			
		||||
        }, []);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
@@ -223,6 +240,9 @@ const store = createStore({
 | 
			
		||||
    addAvailableLocationGroup(state, group) {
 | 
			
		||||
      state.availableLocations.push(group);
 | 
			
		||||
    },
 | 
			
		||||
    setAccompanyingPeriodWorks(state, works) {
 | 
			
		||||
      state.accompanyingPeriodWorks = works;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    addIssueSelected({ commit }, issue) {
 | 
			
		||||
@@ -341,6 +361,17 @@ const store = createStore({
 | 
			
		||||
      }
 | 
			
		||||
      commit("updateLocation", value);
 | 
			
		||||
    },
 | 
			
		||||
    async fetchAccompanyingPeriodWorks({ state, commit }) {
 | 
			
		||||
      const accompanyingPeriodId = state.activity.accompanyingPeriod.id;
 | 
			
		||||
      const url = `/api/1.0/person/accompanying-course/${accompanyingPeriodId}/works.json`;
 | 
			
		||||
      try {
 | 
			
		||||
        const works = await makeFetch("GET", url);
 | 
			
		||||
        // console.log("works", works);
 | 
			
		||||
        commit("setAccompanyingPeriodWorks", works);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error("Failed to fetch accompanying period works:", error);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    getWhoAmI({ commit }) {
 | 
			
		||||
      const url = `/api/1.0/main/whoami.json`;
 | 
			
		||||
      makeFetch("GET", url).then((user) => {
 | 
			
		||||
@@ -353,5 +384,6 @@ const store = createStore({
 | 
			
		||||
store.dispatch("getWhoAmI");
 | 
			
		||||
 | 
			
		||||
prepareLocations(store);
 | 
			
		||||
store.dispatch("fetchAccompanyingPeriodWorks");
 | 
			
		||||
 | 
			
		||||
export default store;
 | 
			
		||||
 
 | 
			
		||||
@@ -126,4 +126,4 @@
 | 
			
		||||
 | 
			
		||||
{% block css %}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_pickentity_type') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,44 +13,44 @@
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
<div class="item-row">
 | 
			
		||||
    <div class="item-col" style="width: unset">
 | 
			
		||||
        {% if document.isPending %}
 | 
			
		||||
            <div class="badge text-bg-info" data-docgen-is-pending="{{ document.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
 | 
			
		||||
        {% elseif document.isFailure %}
 | 
			
		||||
            <div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        <div>
 | 
			
		||||
            {% if activity.accompanyingPeriod is not null and context == 'person' %}
 | 
			
		||||
                <span class="badge bg-primary">
 | 
			
		||||
                        <i class="fa fa-random"></i> {{ activity.accompanyingPeriod.id }}
 | 
			
		||||
                    </span> 
 | 
			
		||||
    <div class="item-two-col-grid">
 | 
			
		||||
        <div class="title">
 | 
			
		||||
            {% if document.isPending %}
 | 
			
		||||
                <div class="badge text-bg-info" data-docgen-is-pending="{{ document.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
 | 
			
		||||
            {% elseif document.isFailure %}
 | 
			
		||||
                <div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            <div class="badge-activity-type">
 | 
			
		||||
                <span class="title_label"></span>
 | 
			
		||||
                <span class="title_action">
 | 
			
		||||
                    {{ activity.type.name | localize_translatable_string }}
 | 
			
		||||
 | 
			
		||||
            <div>
 | 
			
		||||
                <div>
 | 
			
		||||
                    <div class="badge-activity-type-simple">
 | 
			
		||||
                        {{ activity.type.name | localize_translatable_string }}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% if activity.emergency %}
 | 
			
		||||
                        <span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="denomination h2">
 | 
			
		||||
            {{ document.title|chill_print_or_message("No title") }}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if document.hasTemplate %}
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>{{ document.template.name|localize_translatable_string }}</p>
 | 
			
		||||
            <div class="denomination h2">
 | 
			
		||||
                {{ document.title|chill_print_or_message("No title") }}
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="item-col">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
            {% if document.hasTemplate %}
 | 
			
		||||
                <div>
 | 
			
		||||
                    <p>{{ document.template.name|localize_translatable_string }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="aside">
 | 
			
		||||
            <div class="dates row text-end">
 | 
			
		||||
                <span>{{ document.createdAt|format_date('short') }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% if activity.accompanyingPeriod is not null and context == 'person' %}
 | 
			
		||||
                <div class="text-end">
 | 
			
		||||
                    <span class="badge bg-primary">
 | 
			
		||||
                        <i class="fa fa-random"></i> {{ activity.accompanyingPeriod.id }}
 | 
			
		||||
                    </span> 
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -143,7 +143,10 @@ class ListActivitiesByAccompanyingPeriodContext implements
 | 
			
		||||
            array_filter(
 | 
			
		||||
                $works,
 | 
			
		||||
                function ($work) use ($user) {
 | 
			
		||||
                    $workUsernames = array_map(static fn (User $user) => $user['username'], $work['referrers'] ?? []);
 | 
			
		||||
                    $workUsernames = [];
 | 
			
		||||
                    foreach ($work['referrers'] as $referrer) {
 | 
			
		||||
                        $workUsernames[] = $referrer['username'];
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return \in_array($user->getUserIdentifier(), $workUsernames, true);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -102,6 +102,32 @@ activity:
 | 
			
		||||
    Remove a document: Supprimer le document
 | 
			
		||||
    comment: Commentaire
 | 
			
		||||
    deleted: Échange supprimé
 | 
			
		||||
 | 
			
		||||
    errors: Le formulaire contient des erreurs
 | 
			
		||||
    social_issues: Problématiques sociales
 | 
			
		||||
    choose_other_social_issue: Ajouter une autre problématique sociale...
 | 
			
		||||
    social_actions: Actions d'accompagnement
 | 
			
		||||
    select_first_a_social_issue: Sélectionnez d'abord une problématique sociale
 | 
			
		||||
    social_action_list_empty: Aucune action sociale disponible
 | 
			
		||||
    add_persons: Ajouter des personnes concernées
 | 
			
		||||
    bloc_persons: Usagers
 | 
			
		||||
    bloc_persons_associated: Usagers du parcours
 | 
			
		||||
    bloc_persons_not_associated: Tiers non-pro.
 | 
			
		||||
    bloc_thirdparty: Tiers professionnels
 | 
			
		||||
    bloc_users: T(M)S
 | 
			
		||||
    location: Localisation
 | 
			
		||||
    choose_location: Choisissez une localisation
 | 
			
		||||
    choose_location_type: Choisissez un type de localisation
 | 
			
		||||
    create_new_location: Créer une nouvelle localisation
 | 
			
		||||
    location_fields:
 | 
			
		||||
        name: Nom
 | 
			
		||||
        type: Type
 | 
			
		||||
        phonenumber1: Téléphone
 | 
			
		||||
        phonenumber2: Autre téléphone
 | 
			
		||||
        email: Adresse courriel
 | 
			
		||||
    create_address: Créer une adresse
 | 
			
		||||
    edit_address: Modifier l'adresse
 | 
			
		||||
 | 
			
		||||
No documents: Aucun document
 | 
			
		||||
 | 
			
		||||
# activity filter in list page
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
@import '~ChillPersonAssets/chill/scss/mixins.scss';
 | 
			
		||||
@import '~ChillMainAssets/module/bootstrap/shared';
 | 
			
		||||
@import '~ChillPersonAssets/chill/scss/mixins.scss';
 | 
			
		||||
@import 'bootstrap/scss/_badge.scss';
 | 
			
		||||
 | 
			
		||||
.badge-calendar {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
@@ -23,3 +24,35 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.badge-calendar-simple {
 | 
			
		||||
    @extend .badge;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    margin: 0.2rem 0;
 | 
			
		||||
    padding-left: 0;
 | 
			
		||||
    padding-right: 0.5rem;
 | 
			
		||||
 | 
			
		||||
    border-left: 20px groove $chill-l-gray;
 | 
			
		||||
    border-radius: $badge-border-radius;
 | 
			
		||||
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
    background-color: $gray-100;
 | 
			
		||||
 | 
			
		||||
    color: black;
 | 
			
		||||
    font-weight: normal;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    font-weight: normal;
 | 
			
		||||
    font-size: unset;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    text-indent: 5px hanging;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
 | 
			
		||||
    &::before {
 | 
			
		||||
        margin-right: 3px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        left: -0.5px;
 | 
			
		||||
        font-family: ForkAwesome;
 | 
			
		||||
        content: '\f04b';
 | 
			
		||||
        color: $chill-l-gray;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ div.calendar-list {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > a.calendar-list__global {
 | 
			
		||||
        display: inline-block;;
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        padding: 0.2rem;
 | 
			
		||||
        min-width: 2rem;
 | 
			
		||||
        border: 1px solid var(--bs-chill-blue);
 | 
			
		||||
 
 | 
			
		||||
@@ -96,23 +96,23 @@
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <FullCalendar :options="calendarOptions" ref="calendarRef">
 | 
			
		||||
        <template v-slot:eventContent="arg: EventApi">
 | 
			
		||||
            <span :class="eventClasses(arg.event)">
 | 
			
		||||
                <b v-if="arg.event.extendedProps.is === 'remote'">{{
 | 
			
		||||
                    arg.event.title
 | 
			
		||||
        <template v-slot:eventContent="{ event }">
 | 
			
		||||
            <span :class="eventClasses(event)">
 | 
			
		||||
                <b v-if="event.extendedProps.is === 'remote'">{{
 | 
			
		||||
                    event.title
 | 
			
		||||
                }}</b>
 | 
			
		||||
                <b v-else-if="arg.event.extendedProps.is === 'range'"
 | 
			
		||||
                    >{{ arg.timeText }} -
 | 
			
		||||
                    {{ arg.event.extendedProps.locationName }}</b
 | 
			
		||||
                <b v-else-if="event.extendedProps.is === 'range'"
 | 
			
		||||
                    >{{ formatDate(event.startStr) }} -
 | 
			
		||||
                    {{ event.extendedProps.locationName }}</b
 | 
			
		||||
                >
 | 
			
		||||
                <b v-else-if="arg.event.extendedProps.is === 'local'">{{
 | 
			
		||||
                    arg.event.title
 | 
			
		||||
                <b v-else-if="event.extendedProps.is === 'local'">{{
 | 
			
		||||
                    event.title
 | 
			
		||||
                }}</b>
 | 
			
		||||
                <b v-else>no 'is'</b>
 | 
			
		||||
                <a
 | 
			
		||||
                    v-if="arg.event.extendedProps.is === 'range'"
 | 
			
		||||
                    v-if="event.extendedProps.is === 'range'"
 | 
			
		||||
                    class="fa fa-fw fa-times delete"
 | 
			
		||||
                    @click.prevent="onClickDelete(arg.event)"
 | 
			
		||||
                    @click.prevent="onClickDelete(event)"
 | 
			
		||||
                >
 | 
			
		||||
                </a>
 | 
			
		||||
            </span>
 | 
			
		||||
@@ -221,13 +221,12 @@ import type {
 | 
			
		||||
    DatesSetArg,
 | 
			
		||||
    EventInput,
 | 
			
		||||
} from "@fullcalendar/core";
 | 
			
		||||
import { reactive, computed, ref, onMounted } from "vue";
 | 
			
		||||
import { computed, ref, onMounted } from "vue";
 | 
			
		||||
import { useStore } from "vuex";
 | 
			
		||||
import { key } from "./store";
 | 
			
		||||
import FullCalendar from "@fullcalendar/vue3";
 | 
			
		||||
import frLocale from "@fullcalendar/core/locales/fr";
 | 
			
		||||
import interactionPlugin, {
 | 
			
		||||
    DropArg,
 | 
			
		||||
    EventResizeDoneArg,
 | 
			
		||||
} from "@fullcalendar/interaction";
 | 
			
		||||
import timeGridPlugin from "@fullcalendar/timegrid";
 | 
			
		||||
@@ -237,19 +236,13 @@ import {
 | 
			
		||||
    EventDropArg,
 | 
			
		||||
    EventClickArg,
 | 
			
		||||
} from "@fullcalendar/core";
 | 
			
		||||
import {
 | 
			
		||||
    dateToISO,
 | 
			
		||||
    ISOToDate,
 | 
			
		||||
} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
 | 
			
		||||
import { dateToISO, ISOToDate } from "ChillMainAssets/chill/js/date";
 | 
			
		||||
import VueMultiselect from "vue-multiselect";
 | 
			
		||||
import { Location } from "../../../../../ChillMainBundle/Resources/public/types";
 | 
			
		||||
import { Location } from "ChillMainAssets/types";
 | 
			
		||||
import EditLocation from "./Components/EditLocation.vue";
 | 
			
		||||
import { useI18n } from "vue-i18n";
 | 
			
		||||
 | 
			
		||||
const store = useStore(key);
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n();
 | 
			
		||||
 | 
			
		||||
const showWeekends = ref(false);
 | 
			
		||||
const slotDuration = ref("00:15:00");
 | 
			
		||||
const slotMinTime = ref("09:00:00");
 | 
			
		||||
@@ -301,6 +294,11 @@ const nextWeeks = computed((): Weeks[] =>
 | 
			
		||||
    }),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const formatDate = (datetime: string) => {
 | 
			
		||||
    console.log(typeof datetime);
 | 
			
		||||
    return ISOToDate(datetime);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const baseOptions = ref<CalendarOptions>({
 | 
			
		||||
    locale: frLocale,
 | 
			
		||||
    plugins: [interactionPlugin, timeGridPlugin],
 | 
			
		||||
@@ -353,7 +351,7 @@ const pickedLocation = computed<Location | null>({
 | 
			
		||||
 * return the show classes for the event
 | 
			
		||||
 * @param arg
 | 
			
		||||
 */
 | 
			
		||||
const eventClasses = function (arg: EventApi): object {
 | 
			
		||||
const eventClasses = function (): object {
 | 
			
		||||
    return { calendarRangeItems: true };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -431,7 +429,6 @@ function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
 | 
			
		||||
    if (payload.event.extendedProps.is !== "range") {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const changedEvent = payload.event;
 | 
			
		||||
 | 
			
		||||
    store.dispatch("calendarRanges/patchRangeTime", {
 | 
			
		||||
        calendarRangeId: payload.event.extendedProps.calendarRangeId,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,50 +6,48 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<div class="item-row">
 | 
			
		||||
    <div class="item-col" style="width: unset">
 | 
			
		||||
        {% if document.storedObject.isPending %}
 | 
			
		||||
            <div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
 | 
			
		||||
        {% elseif document.storedObject.isFailure %}
 | 
			
		||||
            <div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        <div>
 | 
			
		||||
            {% if c.accompanyingPeriod is not null and context == 'person' %}
 | 
			
		||||
                <span class="badge bg-primary">
 | 
			
		||||
                        <i class="fa fa-random"></i> {{ c.accompanyingPeriod.id }}
 | 
			
		||||
                    </span> 
 | 
			
		||||
    <div class="item-two-col-grid">
 | 
			
		||||
        <div class="title">
 | 
			
		||||
            {% if document.storedObject.isPending %}
 | 
			
		||||
                <div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
 | 
			
		||||
            {% elseif document.storedObject.isFailure %}
 | 
			
		||||
                <div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
 | 
			
		||||
            <span class="badge-calendar">
 | 
			
		||||
                    <span class="title_label"></span>
 | 
			
		||||
                    <span class="title_action">
 | 
			
		||||
                        {{ 'Calendar'|trans }}
 | 
			
		||||
                        {% if c.endDate.diff(c.startDate).days >= 1 %}
 | 
			
		||||
                            {{ c.startDate|format_datetime('short', 'short') }}
 | 
			
		||||
                            - {{ c.endDate|format_datetime('short', 'short') }}
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            {{ c.startDate|format_datetime('short', 'short') }}
 | 
			
		||||
                            - {{ c.endDate|format_datetime('none', 'short') }}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </span>
 | 
			
		||||
                </span>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="denomination h2">
 | 
			
		||||
            {{ document.storedObject.title|chill_print_or_message("No title") }}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if document.storedObject.hasTemplate %}
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="item-col">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
                <span class="badge-calendar-simple">
 | 
			
		||||
                    {{ 'Calendar'|trans }}
 | 
			
		||||
                    {% if c.endDate.diff(c.startDate).days >= 1 %}
 | 
			
		||||
                        {{ c.startDate|format_datetime('short', 'short') }}
 | 
			
		||||
                        - {{ c.endDate|format_datetime('short', 'short') }}
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                        {{ c.startDate|format_datetime('short', 'short') }}
 | 
			
		||||
                        - {{ c.endDate|format_datetime('none', 'short') }}
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="denomination h2">
 | 
			
		||||
                {{ document.storedObject.title|chill_print_or_message("No title") }}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% if document.storedObject.hasTemplate %}
 | 
			
		||||
                <div>
 | 
			
		||||
                    <p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="aside">
 | 
			
		||||
            <div class="dates row text-end">
 | 
			
		||||
                <span>{{ document.storedObject.createdAt|format_date('short') }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% if c.accompanyingPeriod is not null and context == 'person' %}
 | 
			
		||||
                <div class="text-end">
 | 
			
		||||
                    <span class="badge bg-primary">
 | 
			
		||||
                        <i class="fa fa-random"></i> {{ c.accompanyingPeriod.id }}
 | 
			
		||||
                    </span> 
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,9 @@ const startApp = (
 | 
			
		||||
    collectionEntry: null | HTMLLIElement,
 | 
			
		||||
): void => {
 | 
			
		||||
    console.log("app started", divElement);
 | 
			
		||||
 | 
			
		||||
    const inputTitle = collectionEntry?.querySelector("input[type='text']");
 | 
			
		||||
 | 
			
		||||
    const input_stored_object: HTMLInputElement | null =
 | 
			
		||||
        divElement.querySelector("input[data-stored-object]");
 | 
			
		||||
    if (null === input_stored_object) {
 | 
			
		||||
@@ -26,9 +29,10 @@ const startApp = (
 | 
			
		||||
    const app = createApp({
 | 
			
		||||
        template:
 | 
			
		||||
            '<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>',
 | 
			
		||||
        data(vm) {
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                existingDoc: existingDoc,
 | 
			
		||||
                inputTitle: inputTitle,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        components: {
 | 
			
		||||
@@ -38,10 +42,13 @@ const startApp = (
 | 
			
		||||
            addDocument: function ({
 | 
			
		||||
                stored_object,
 | 
			
		||||
                stored_object_version,
 | 
			
		||||
                file_name,
 | 
			
		||||
            }: {
 | 
			
		||||
                stored_object: StoredObject;
 | 
			
		||||
                stored_object_version: StoredObjectVersion;
 | 
			
		||||
                file_name: string;
 | 
			
		||||
            }): void {
 | 
			
		||||
                stored_object.title = file_name;
 | 
			
		||||
                console.log("object added", stored_object);
 | 
			
		||||
                console.log("version added", stored_object_version);
 | 
			
		||||
                this.$data.existingDoc = stored_object;
 | 
			
		||||
@@ -49,6 +56,11 @@ const startApp = (
 | 
			
		||||
                input_stored_object.value = JSON.stringify(
 | 
			
		||||
                    this.$data.existingDoc,
 | 
			
		||||
                );
 | 
			
		||||
                if (this.$data.inputTitle) {
 | 
			
		||||
                    if (!this.$data.inputTitle?.value) {
 | 
			
		||||
                        this.$data.inputTitle.value = file_name;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            removeDocument: function (object: StoredObject): void {
 | 
			
		||||
                console.log("catch remove document", object);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,26 +2,28 @@
 | 
			
		||||
    <teleport to="body">
 | 
			
		||||
        <modal v-if="modalOpen" @close="modalOpen = false">
 | 
			
		||||
            <template v-slot:header>
 | 
			
		||||
                <h2>{{ $t("signature_confirmation") }}</h2>
 | 
			
		||||
                <h2>{{ trans(SIGNATURES_SIGNATURE_CONFIRMATION) }}</h2>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-slot:body>
 | 
			
		||||
                <div class="signature-modal-body text-center" v-if="loading">
 | 
			
		||||
                    <p>{{ $t("electronic_signature_in_progress") }}</p>
 | 
			
		||||
                    <p>
 | 
			
		||||
                        {{ trans(SIGNATURES_ELECTRONIC_SIGNATURE_IN_PROGRESS) }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <div class="loading">
 | 
			
		||||
                        <i
 | 
			
		||||
                            class="fa fa-circle-o-notch fa-spin fa-3x"
 | 
			
		||||
                            :title="$t('loading')"
 | 
			
		||||
                            :title="trans(SIGNATURES_LOADING)"
 | 
			
		||||
                        ></i>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="signature-modal-body text-center" v-else>
 | 
			
		||||
                    <p>{{ $t("you_are_going_to_sign") }}</p>
 | 
			
		||||
                    <p>{{ $t("are_you_sure") }}</p>
 | 
			
		||||
                    <p>{{ trans(SIGNATURES_YOU_ARE_GOING_TO_SIGN) }}</p>
 | 
			
		||||
                    <p>{{ trans(SIGNATURES_ARE_YOU_SURE) }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-slot:footer>
 | 
			
		||||
                <button class="btn btn-action" @click.prevent="confirmSign">
 | 
			
		||||
                    {{ $t("yes") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_YES) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </modal>
 | 
			
		||||
@@ -82,33 +84,39 @@
 | 
			
		||||
                        @change="toggleMultiPage"
 | 
			
		||||
                    />
 | 
			
		||||
                    <label class="form-check-label" for="checkboxMulti">
 | 
			
		||||
                        {{ $t("all_pages") }}
 | 
			
		||||
                        {{ trans(SIGNATURES_ALL_PAGES) }}
 | 
			
		||||
                    </label>
 | 
			
		||||
                </template>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div
 | 
			
		||||
                v-if="signature.zones.length > 0"
 | 
			
		||||
                v-if="signature.zones.length === 1 && signedState !== 'signed'"
 | 
			
		||||
                class="col-5 p-0 text-center turnSignature"
 | 
			
		||||
            >
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="
 | 
			
		||||
                        userSignatureZone === null ||
 | 
			
		||||
                        userSignatureZone?.index < 1
 | 
			
		||||
                    "
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="goToSignatureZoneUnique"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div
 | 
			
		||||
                v-if="signature.zones.length > 1"
 | 
			
		||||
                class="col-5 p-0 text-center turnSignature"
 | 
			
		||||
            >
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="isFirstSignatureZone()"
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(-1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("last_zone") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_LAST_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <span>|</span>
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="
 | 
			
		||||
                        userSignatureZone?.index >= signature.zones.length - 1
 | 
			
		||||
                    "
 | 
			
		||||
                    :disabled="isLastSignatureZone()"
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("next_zone") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_NEXT_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col text-end" v-if="signedState !== 'signed'">
 | 
			
		||||
@@ -117,9 +125,9 @@
 | 
			
		||||
                    :hidden="!userSignatureZone"
 | 
			
		||||
                    @click="undoSign"
 | 
			
		||||
                    v-if="signature.zones.length > 1"
 | 
			
		||||
                    :title="$t('choose_another_signature')"
 | 
			
		||||
                    :title="trans(SIGNATURES_CHOOSE_ANOTHER_SIGNATURE)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("another_zone") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_ANOTHER_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <button
 | 
			
		||||
                    class="btn btn-misc btn-sm"
 | 
			
		||||
@@ -127,7 +135,7 @@
 | 
			
		||||
                    @click="undoSign"
 | 
			
		||||
                    v-else
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("cancel") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_CANCEL) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <button
 | 
			
		||||
                    v-if="userSignatureZone === null"
 | 
			
		||||
@@ -139,7 +147,7 @@
 | 
			
		||||
                        active: canvasEvent === 'add',
 | 
			
		||||
                    }"
 | 
			
		||||
                    @click="toggleAddZone()"
 | 
			
		||||
                    :title="$t('add_sign_zone')"
 | 
			
		||||
                    :title="trans(SIGNATURES_ADD_SIGN_ZONE)"
 | 
			
		||||
                >
 | 
			
		||||
                    <template v-if="canvasEvent === 'add'">
 | 
			
		||||
                        <div
 | 
			
		||||
@@ -191,58 +199,70 @@
 | 
			
		||||
                        @change="toggleMultiPage"
 | 
			
		||||
                    />
 | 
			
		||||
                    <label class="form-check-label" for="checkboxMulti">
 | 
			
		||||
                        {{ $t("see_all_pages") }}
 | 
			
		||||
                        {{ trans(SIGNATURES_SEE_ALL_PAGES) }}
 | 
			
		||||
                    </label>
 | 
			
		||||
                </template>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div
 | 
			
		||||
                v-if="signature.zones.length > 0 && signedState !== 'signed'"
 | 
			
		||||
                v-if="signature.zones.length === 1 && signedState !== 'signed'"
 | 
			
		||||
                class="col-4 d-xl-none text-center turnSignature p-0"
 | 
			
		||||
            >
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="
 | 
			
		||||
                        userSignatureZone === null ||
 | 
			
		||||
                        userSignatureZone?.index < 1
 | 
			
		||||
                    "
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(-1)"
 | 
			
		||||
                    @click="goToSignatureZoneUnique"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("last_zone") }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <span>|</span>
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="
 | 
			
		||||
                        userSignatureZone?.index >= signature.zones.length - 1
 | 
			
		||||
                    "
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("next_zone") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div
 | 
			
		||||
                v-if="signature.zones.length > 0 && signedState !== 'signed'"
 | 
			
		||||
                class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
 | 
			
		||||
                v-if="signature.zones.length > 1 && signedState !== 'signed'"
 | 
			
		||||
                class="col-4 d-xl-none text-center turnSignature p-0"
 | 
			
		||||
            >
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="
 | 
			
		||||
                        userSignatureZone === null ||
 | 
			
		||||
                        userSignatureZone?.index < 1
 | 
			
		||||
                    "
 | 
			
		||||
                    :disabled="isFirstSignatureZone()"
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(-1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("last_sign_zone") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_LAST_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <span>|</span>
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="
 | 
			
		||||
                        userSignatureZone?.index >= signature.zones.length - 1
 | 
			
		||||
                    "
 | 
			
		||||
                    :disabled="isLastSignatureZone()"
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("next_sign_zone") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_NEXT_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div
 | 
			
		||||
                v-if="signature.zones.length === 1 && signedState !== 'signed'"
 | 
			
		||||
                class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
 | 
			
		||||
            >
 | 
			
		||||
                <button
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="goToSignatureZoneUnique"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div
 | 
			
		||||
                v-if="signature.zones.length > 1 && signedState !== 'signed'"
 | 
			
		||||
                class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
 | 
			
		||||
            >
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="isFirstSignatureZone()"
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(-1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ trans(SIGNATURES_LAST_SIGN_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <span>|</span>
 | 
			
		||||
                <button
 | 
			
		||||
                    :disabled="isLastSignatureZone()"
 | 
			
		||||
                    class="btn btn-light btn-sm"
 | 
			
		||||
                    @click="turnSignature(1)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ trans(SIGNATURES_NEXT_SIGN_ZONE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col text-end" v-if="signedState !== 'signed'">
 | 
			
		||||
@@ -252,7 +272,7 @@
 | 
			
		||||
                    @click="undoSign"
 | 
			
		||||
                    v-if="signature.zones.length > 1"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("choose_another_signature") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_CHOOSE_ANOTHER_SIGNATURE) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <button
 | 
			
		||||
                    class="btn btn-misc btn-sm"
 | 
			
		||||
@@ -260,7 +280,7 @@
 | 
			
		||||
                    @click="undoSign"
 | 
			
		||||
                    v-else
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("cancel") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_CANCEL) }}
 | 
			
		||||
                </button>
 | 
			
		||||
                <button
 | 
			
		||||
                    v-if="userSignatureZone === null"
 | 
			
		||||
@@ -272,13 +292,13 @@
 | 
			
		||||
                        active: canvasEvent === 'add',
 | 
			
		||||
                    }"
 | 
			
		||||
                    @click="toggleAddZone()"
 | 
			
		||||
                    :title="$t('add_sign_zone')"
 | 
			
		||||
                    :title="trans(SIGNATURES_ADD_SIGN_ZONE)"
 | 
			
		||||
                >
 | 
			
		||||
                    <template v-if="canvasEvent !== 'add'">
 | 
			
		||||
                        {{ $t("add_zone") }}
 | 
			
		||||
                        {{ trans(SIGNATURES_ADD_ZONE) }}
 | 
			
		||||
                    </template>
 | 
			
		||||
                    <template v-else>
 | 
			
		||||
                        {{ $t("click_on_document") }}
 | 
			
		||||
                        {{ trans(SIGNATURES_CLICK_ON_DOCUMENT) }}
 | 
			
		||||
                        <div
 | 
			
		||||
                            class="spinner-border spinner-border-sm"
 | 
			
		||||
                            role="status"
 | 
			
		||||
@@ -312,10 +332,10 @@
 | 
			
		||||
                    v-if="signedState !== 'signed'"
 | 
			
		||||
                    :href="getReturnPath()"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("cancel") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_CANCEL) }}
 | 
			
		||||
                </a>
 | 
			
		||||
                <a class="btn btn-misc" v-else :href="getReturnPath()">
 | 
			
		||||
                    {{ $t("return") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_RETURN) }}
 | 
			
		||||
                </a>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col text-end" v-if="signedState !== 'signed'">
 | 
			
		||||
@@ -324,7 +344,7 @@
 | 
			
		||||
                    :disabled="!userSignatureZone"
 | 
			
		||||
                    @click="sign"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t("sign") }}
 | 
			
		||||
                    {{ trans(SIGNATURES_SIGN) }}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-4" v-else></div>
 | 
			
		||||
@@ -333,7 +353,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, Ref, reactive } from "vue";
 | 
			
		||||
import { ref, Ref } from "vue";
 | 
			
		||||
import { useToast } from "vue-toast-notification";
 | 
			
		||||
import "vue-toast-notification/dist/theme-sugar.css";
 | 
			
		||||
import {
 | 
			
		||||
@@ -344,25 +364,47 @@ import {
 | 
			
		||||
    SignedState,
 | 
			
		||||
    ZoomLevel,
 | 
			
		||||
} from "../../types";
 | 
			
		||||
import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
 | 
			
		||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
 | 
			
		||||
import * as pdfjsLib from "pdfjs-dist";
 | 
			
		||||
import {
 | 
			
		||||
    PDFDocumentProxy,
 | 
			
		||||
    PDFPageProxy,
 | 
			
		||||
} from "pdfjs-dist/types/src/display/api";
 | 
			
		||||
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
import {
 | 
			
		||||
    SIGNATURES_YES,
 | 
			
		||||
    SIGNATURES_ARE_YOU_SURE,
 | 
			
		||||
    SIGNATURES_YOU_ARE_GOING_TO_SIGN,
 | 
			
		||||
    SIGNATURES_SIGNATURE_CONFIRMATION,
 | 
			
		||||
    SIGNATURES_SIGN,
 | 
			
		||||
    SIGNATURES_CHOOSE_ANOTHER_SIGNATURE,
 | 
			
		||||
    SIGNATURES_CANCEL,
 | 
			
		||||
    SIGNATURES_LAST_SIGN_ZONE,
 | 
			
		||||
    SIGNATURES_NEXT_SIGN_ZONE,
 | 
			
		||||
    SIGNATURES_ADD_SIGN_ZONE,
 | 
			
		||||
    SIGNATURES_CLICK_ON_DOCUMENT,
 | 
			
		||||
    SIGNATURES_LAST_ZONE,
 | 
			
		||||
    SIGNATURES_NEXT_ZONE,
 | 
			
		||||
    SIGNATURES_ADD_ZONE,
 | 
			
		||||
    SIGNATURES_ANOTHER_ZONE,
 | 
			
		||||
    SIGNATURES_ELECTRONIC_SIGNATURE_IN_PROGRESS,
 | 
			
		||||
    SIGNATURES_LOADING,
 | 
			
		||||
    SIGNATURES_RETURN,
 | 
			
		||||
    SIGNATURES_SEE_ALL_PAGES,
 | 
			
		||||
    SIGNATURES_ALL_PAGES,
 | 
			
		||||
    SIGNATURES_GO_TO_SIGNATURE_UNIQUE,
 | 
			
		||||
    trans,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
// @ts-ignore incredible but the console.log is needed
 | 
			
		||||
import * as PdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
 | 
			
		||||
console.log(PdfWorker); // incredible but this is needed
 | 
			
		||||
console.log(PdfWorker);
 | 
			
		||||
 | 
			
		||||
// import { PdfWorker } from 'pdfjs-dist/build/pdf.worker.mjs'
 | 
			
		||||
// pdfjsLib.GlobalWorkerOptions.workerSrc = PdfWorker;
 | 
			
		||||
 | 
			
		||||
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
 | 
			
		||||
import {
 | 
			
		||||
    download_and_decrypt_doc,
 | 
			
		||||
    download_doc_as_pdf,
 | 
			
		||||
} from "../StoredObjectButton/helpers";
 | 
			
		||||
import { download_doc_as_pdf } from "../StoredObjectButton/helpers";
 | 
			
		||||
 | 
			
		||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs-dist/build/pdf.worker.mjs";
 | 
			
		||||
 | 
			
		||||
@@ -433,6 +475,16 @@ const $toast = useToast();
 | 
			
		||||
 | 
			
		||||
const signature = window.signature;
 | 
			
		||||
 | 
			
		||||
const isFirstSignatureZone = () =>
 | 
			
		||||
    userSignatureZone.value?.index != null
 | 
			
		||||
        ? userSignatureZone.value.index < 1
 | 
			
		||||
        : false;
 | 
			
		||||
 | 
			
		||||
const isLastSignatureZone = () =>
 | 
			
		||||
    userSignatureZone.value?.index
 | 
			
		||||
        ? userSignatureZone.value.index >= signature.zones.length - 1
 | 
			
		||||
        : false;
 | 
			
		||||
 | 
			
		||||
const setZoomLevel = async (zoomLevel: string) => {
 | 
			
		||||
    zoom.value = Number.parseFloat(zoomLevel);
 | 
			
		||||
    await resetPages();
 | 
			
		||||
@@ -604,6 +656,15 @@ const turnPage = async (upOrDown: number) => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const selectZoneInCanvas = (signatureZone: SignatureZone) => {
 | 
			
		||||
    page.value = signatureZone.PDFPage.index + 1;
 | 
			
		||||
    const canvas = getCanvas(signatureZone.PDFPage.index + 1);
 | 
			
		||||
    selectZone(signatureZone, canvas);
 | 
			
		||||
    canvas.scrollIntoView();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const goToSignatureZoneUnique = () => selectZoneInCanvas(signature.zones[0]);
 | 
			
		||||
 | 
			
		||||
const turnSignature = async (upOrDown: number) => {
 | 
			
		||||
    let zoneIndex = userSignatureZone.value?.index ?? -1;
 | 
			
		||||
    if (zoneIndex < -1) {
 | 
			
		||||
@@ -616,10 +677,7 @@ const turnSignature = async (upOrDown: number) => {
 | 
			
		||||
    }
 | 
			
		||||
    let currentZone = signature.zones[zoneIndex];
 | 
			
		||||
    if (currentZone) {
 | 
			
		||||
        page.value = currentZone.PDFPage.index + 1;
 | 
			
		||||
        const canvas = getCanvas(currentZone.PDFPage.index + 1);
 | 
			
		||||
        selectZone(currentZone, canvas);
 | 
			
		||||
        canvas.scrollIntoView();
 | 
			
		||||
        selectZoneInCanvas(currentZone);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -754,7 +812,7 @@ const confirmSign = () => {
 | 
			
		||||
        zone: userSignatureZone.value,
 | 
			
		||||
    };
 | 
			
		||||
    makeFetch("POST", url, body)
 | 
			
		||||
        .then((r) => {
 | 
			
		||||
        .then(() => {
 | 
			
		||||
            checkForReady();
 | 
			
		||||
        })
 | 
			
		||||
        .catch((error) => {
 | 
			
		||||
@@ -776,9 +834,7 @@ const undoSign = async () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const toggleAddZone = () => {
 | 
			
		||||
    canvasEvent.value === "select"
 | 
			
		||||
        ? (canvasEvent.value = "add")
 | 
			
		||||
        : (canvasEvent.value = "select");
 | 
			
		||||
    canvasEvent.value = canvasEvent.value === "select" ? "add" : "select";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addZoneEvent = async (e: PointerEvent, canvas: HTMLCanvasElement) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ const emit =
 | 
			
		||||
            {
 | 
			
		||||
                stored_object_version: StoredObjectVersionCreated,
 | 
			
		||||
                stored_object: StoredObject,
 | 
			
		||||
                file_name: string,
 | 
			
		||||
            },
 | 
			
		||||
        ) => void
 | 
			
		||||
    >();
 | 
			
		||||
@@ -114,7 +115,21 @@ const handleFile = async (file: File): Promise<void> => {
 | 
			
		||||
        persisted: false,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    emit("addDocument", { stored_object, stored_object_version });
 | 
			
		||||
    const fileName = file.name;
 | 
			
		||||
    let file_name = "Nouveau document";
 | 
			
		||||
    const file_name_split = fileName.split(".");
 | 
			
		||||
    if (file_name_split.length > 1) {
 | 
			
		||||
        const extension = file_name_split
 | 
			
		||||
            ? file_name_split[file_name_split.length - 1]
 | 
			
		||||
            : "";
 | 
			
		||||
        file_name = fileName.replace(extension, "").slice(0, -1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    emit("addDocument", {
 | 
			
		||||
        stored_object,
 | 
			
		||||
        stored_object_version,
 | 
			
		||||
        file_name: file_name,
 | 
			
		||||
    });
 | 
			
		||||
    uploading.value = false;
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ const emit = defineEmits<{
 | 
			
		||||
        {
 | 
			
		||||
            stored_object: StoredObject,
 | 
			
		||||
            stored_object_version: StoredObjectVersion,
 | 
			
		||||
            file_name: string,
 | 
			
		||||
        },
 | 
			
		||||
    ): void;
 | 
			
		||||
    (e: "removeDocument"): void;
 | 
			
		||||
@@ -42,14 +43,16 @@ const buttonState = computed<"add" | "replace">(() => {
 | 
			
		||||
function onAddDocument({
 | 
			
		||||
    stored_object,
 | 
			
		||||
    stored_object_version,
 | 
			
		||||
    file_name,
 | 
			
		||||
}: {
 | 
			
		||||
    stored_object: StoredObject;
 | 
			
		||||
    stored_object_version: StoredObjectVersion;
 | 
			
		||||
    file_name: string;
 | 
			
		||||
}): void {
 | 
			
		||||
    const message =
 | 
			
		||||
        buttonState.value === "add" ? "Document ajouté" : "Document remplacé";
 | 
			
		||||
    $toast.success(message);
 | 
			
		||||
    emit("addDocument", { stored_object_version, stored_object });
 | 
			
		||||
    emit("addDocument", { stored_object_version, stored_object, file_name });
 | 
			
		||||
    state.showModal = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ const emit = defineEmits<{
 | 
			
		||||
        {
 | 
			
		||||
            stored_object: StoredObject,
 | 
			
		||||
            stored_object_version: StoredObjectVersion,
 | 
			
		||||
            file_name: string,
 | 
			
		||||
        },
 | 
			
		||||
    ): void;
 | 
			
		||||
    (e: "removeDocument"): void;
 | 
			
		||||
@@ -53,11 +54,13 @@ const dav_link_href = computed<string | undefined>(() => {
 | 
			
		||||
const onAddDocument = ({
 | 
			
		||||
    stored_object,
 | 
			
		||||
    stored_object_version,
 | 
			
		||||
    file_name,
 | 
			
		||||
}: {
 | 
			
		||||
    stored_object: StoredObject;
 | 
			
		||||
    stored_object_version: StoredObjectVersion;
 | 
			
		||||
    file_name: string;
 | 
			
		||||
}): void => {
 | 
			
		||||
    emit("addDocument", { stored_object, stored_object_version });
 | 
			
		||||
    emit("addDocument", { stored_object, stored_object_version, file_name });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onRemoveDocument = (e: Event): void => {
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ const onRestored = ({
 | 
			
		||||
<template>
 | 
			
		||||
    <template v-if="props.versions.length > 0">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
            <template v-for="v in props.versions">
 | 
			
		||||
            <template v-for="v in props.versions" :key="v.id">
 | 
			
		||||
                <history-button-list-item
 | 
			
		||||
                    :version="v"
 | 
			
		||||
                    :can-edit="canEdit"
 | 
			
		||||
 
 | 
			
		||||
@@ -32,13 +32,17 @@ const onRestore = ({
 | 
			
		||||
    emit("restoreVersion", { newVersion });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const isKeptBeforeConversion = computed<boolean>(() =>
 | 
			
		||||
    props.version["point-in-times"].reduce(
 | 
			
		||||
        (accumulator: boolean, pit: StoredObjectPointInTime) =>
 | 
			
		||||
            accumulator || "keep-before-conversion" === pit.reason,
 | 
			
		||||
        false,
 | 
			
		||||
    ),
 | 
			
		||||
);
 | 
			
		||||
const isKeptBeforeConversion = computed<boolean>(() => {
 | 
			
		||||
    if ("point-in-times" in props.version) {
 | 
			
		||||
        return props.version["point-in-times"].reduce(
 | 
			
		||||
            (accumulator: boolean, pit: StoredObjectPointInTime) =>
 | 
			
		||||
                accumulator || "keep-before-conversion" === pit.reason,
 | 
			
		||||
            false,
 | 
			
		||||
        );
 | 
			
		||||
    } else {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const isRestored = computed<boolean>(
 | 
			
		||||
    () => props.version.version > 0 && null !== props.version["from-restored"],
 | 
			
		||||
@@ -90,11 +94,11 @@ const classes = computed<{
 | 
			
		||||
        <div class="col-12">
 | 
			
		||||
            <file-icon :type="version.type"></file-icon>
 | 
			
		||||
            <span
 | 
			
		||||
                ><strong>#{{ version.version + 1 }}</strong></span
 | 
			
		||||
                ><strong> #{{ version.version + 1 }} </strong></span
 | 
			
		||||
            >
 | 
			
		||||
            <template
 | 
			
		||||
                v-if="version.createdBy !== null && version.createdAt !== null"
 | 
			
		||||
                ><strong v-if="version.version == 0">Créé par</strong
 | 
			
		||||
                ><strong v-if="version.version == 0">créé par</strong
 | 
			
		||||
                ><strong v-else>modifié par</strong>
 | 
			
		||||
                <span class="badge-user"
 | 
			
		||||
                    ><UserRenderBoxBadge
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,10 @@ const open = () => {
 | 
			
		||||
    state.opened = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onRestoreVersion = (payload: {
 | 
			
		||||
    newVersion: StoredObjectVersionWithPointInTime;
 | 
			
		||||
}) => emit("restoreVersion", payload);
 | 
			
		||||
 | 
			
		||||
defineExpose({ open });
 | 
			
		||||
</script>
 | 
			
		||||
<template>
 | 
			
		||||
@@ -42,9 +46,7 @@ defineExpose({ open });
 | 
			
		||||
                    :versions="props.versions"
 | 
			
		||||
                    :can-edit="canEdit"
 | 
			
		||||
                    :stored-object="storedObject"
 | 
			
		||||
                    @restore-version="
 | 
			
		||||
                        (payload) => emit('restoreVersion', payload)
 | 
			
		||||
                    "
 | 
			
		||||
                    @restore-version="onRestoreVersion"
 | 
			
		||||
                ></history-button-list>
 | 
			
		||||
            </template>
 | 
			
		||||
        </modal>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ License * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
{{ encore_entry_link_tags("mod_document_action_buttons_group") }}
 | 
			
		||||
{% endblock %} {% block content %}
 | 
			
		||||
 | 
			
		||||
<div class="col-md-10 col-xxl">
 | 
			
		||||
<div class="document-list">
 | 
			
		||||
    <h1>
 | 
			
		||||
        {{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
 | 
			
		||||
    </h1>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,54 +3,56 @@
 | 
			
		||||
{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
 | 
			
		||||
 | 
			
		||||
<div class="item-row">
 | 
			
		||||
    <div class="item-col" style="width: unset">
 | 
			
		||||
        {% if document.object.isPending %}
 | 
			
		||||
            <div class="badge text-bg-info" data-docgen-is-pending="{{ document.object.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
 | 
			
		||||
        {% elseif document.object.isFailure %}
 | 
			
		||||
            <div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    <!-- person document or accompanying course document -->
 | 
			
		||||
    <div class="item-two-col-grid">
 | 
			
		||||
        <div class="title">
 | 
			
		||||
            {% if document.object.isPending %}
 | 
			
		||||
                <div class="badge text-bg-info" data-docgen-is-pending="{{ document.object.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
 | 
			
		||||
            {% elseif document.object.isFailure %}
 | 
			
		||||
                <div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if context == 'person' and accompanyingCourse is defined %}
 | 
			
		||||
            <div>
 | 
			
		||||
                    <span class="badge bg-primary">
 | 
			
		||||
                        <i class="fa fa-random"></i> {{ accompanyingCourse.id }}
 | 
			
		||||
                    </span> 
 | 
			
		||||
            <div class="denomination h2">
 | 
			
		||||
                {{ document.title|chill_print_or_message("No title") }}
 | 
			
		||||
            </div>
 | 
			
		||||
        {% elseif context == 'accompanying-period' and person is defined %}
 | 
			
		||||
            <div>
 | 
			
		||||
                    <span class="badge bg-primary">
 | 
			
		||||
                        {{  'Document from person %name%'|trans({ '%name%': document.person|chill_entity_render_string }) }}
 | 
			
		||||
                    </span> 
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <div class="denomination h2">
 | 
			
		||||
            {{ document.title|chill_print_or_message("No title") }}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if document.object.type is not empty %}
 | 
			
		||||
            <div>
 | 
			
		||||
                {{ mm.mimeIcon(document.object.type) }}
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <div>
 | 
			
		||||
            <p>{{ document.category.name|localize_translatable_string }}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if document.object.hasTemplate %}
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>{{ document.object.template.name|localize_translatable_string }}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="item-col">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
            {% if document.date is not null %}
 | 
			
		||||
                <div class="dates row text-end">
 | 
			
		||||
                    <span>{{ document.date|format_date('short') }}</span>
 | 
			
		||||
            {% if document.object.type is not empty %}
 | 
			
		||||
                <div>
 | 
			
		||||
                    {{ mm.mimeIcon(document.object.type) }}
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% if document.category %}
 | 
			
		||||
                <div>
 | 
			
		||||
                    <p>{{ document.category.name|localize_translatable_string }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% if document.object.hasTemplate %}
 | 
			
		||||
                <div>
 | 
			
		||||
                    <p>{{ document.object.template.name|localize_translatable_string }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if document.date is not null %}
 | 
			
		||||
            <div class="aside">
 | 
			
		||||
                <div class="dates row text-end">
 | 
			
		||||
                    <span>{{ document.date|format_date('short') }}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
                {% if context == 'person' and accompanyingCourse is defined %}
 | 
			
		||||
                    <div class="text-end">
 | 
			
		||||
                        <span class="badge bg-primary">
 | 
			
		||||
                            <i class="fa fa-random"></i> {{ accompanyingCourse.id }}
 | 
			
		||||
                        </span> 
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% elseif context == 'accompanying-period' and person is defined %}
 | 
			
		||||
                    <div class="text-end">
 | 
			
		||||
                        <span class="badge bg-primary">
 | 
			
		||||
                             {{ document.person|chill_entity_render_string }}
 | 
			
		||||
                        </span> 
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
{% if document.description is not empty %}
 | 
			
		||||
    <div class="item-row">
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,15 @@ final readonly class RemoveOldVersionMessageHandler implements MessageHandlerInt
 | 
			
		||||
 | 
			
		||||
        $storedObject = $storedObjectVersion->getStoredObject();
 | 
			
		||||
 | 
			
		||||
        $this->storedObjectManager->delete($storedObjectVersion);
 | 
			
		||||
        if ($this->storedObjectManager->exists($storedObjectVersion)) {
 | 
			
		||||
            $this->storedObjectManager->delete($storedObjectVersion);
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->logger->notice(
 | 
			
		||||
                self::LOG_PREFIX.'Stored object version does not exists any more.',
 | 
			
		||||
                ['storedObjectVersionName' => $storedObjectVersion->getFilename()],
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // to ensure an immediate deletion
 | 
			
		||||
        $this->entityManager->remove($storedObjectVersion);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ class RemoveOldVersionMessageHandlerTest extends TestCase
 | 
			
		||||
        $entityManager->expects($this->once())->method('clear');
 | 
			
		||||
 | 
			
		||||
        $storedObjectManager = $this->createMock(StoredObjectManagerInterface::class);
 | 
			
		||||
        $storedObjectManager->expects($this->once())->method('exists')->willReturn(true);
 | 
			
		||||
        $storedObjectManager->expects($this->once())->method('delete')->with($this->identicalTo($version));
 | 
			
		||||
 | 
			
		||||
        $handler = new RemoveOldVersionMessageHandler($storedObjectVersionRepository, new NullLogger(), $entityManager, $storedObjectManager, new MockClock());
 | 
			
		||||
@@ -51,6 +52,29 @@ class RemoveOldVersionMessageHandlerTest extends TestCase
 | 
			
		||||
        $handler(new RemoveOldVersionMessage(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testInvokeForVersionNotExisting(): void
 | 
			
		||||
    {
 | 
			
		||||
        $object = new StoredObject();
 | 
			
		||||
        $version = $object->registerVersion();
 | 
			
		||||
        $storedObjectVersionRepository = $this->createMock(StoredObjectVersionRepository::class);
 | 
			
		||||
        $storedObjectVersionRepository->expects($this->once())->method('find')
 | 
			
		||||
            ->with($this->identicalTo(1))
 | 
			
		||||
            ->willReturn($version);
 | 
			
		||||
 | 
			
		||||
        $entityManager = $this->createMock(EntityManagerInterface::class);
 | 
			
		||||
        $entityManager->expects($this->once())->method('remove')->with($this->identicalTo($version));
 | 
			
		||||
        $entityManager->expects($this->once())->method('flush');
 | 
			
		||||
        $entityManager->expects($this->once())->method('clear');
 | 
			
		||||
 | 
			
		||||
        $storedObjectManager = $this->createMock(StoredObjectManagerInterface::class);
 | 
			
		||||
        $storedObjectManager->expects($this->once())->method('exists')->willReturn(false);
 | 
			
		||||
        $storedObjectManager->expects($this->never())->method('delete')->with($this->identicalTo($version));
 | 
			
		||||
 | 
			
		||||
        $handler = new RemoveOldVersionMessageHandler($storedObjectVersionRepository, new NullLogger(), $entityManager, $storedObjectManager, new MockClock());
 | 
			
		||||
 | 
			
		||||
        $handler(new RemoveOldVersionMessage(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testInvokeWithStoredObjectToDelete(): void
 | 
			
		||||
    {
 | 
			
		||||
        $object = new StoredObject();
 | 
			
		||||
@@ -123,6 +147,6 @@ class DummyStoredObjectManager implements StoredObjectManagerInterface
 | 
			
		||||
 | 
			
		||||
    public function exists(StoredObject|StoredObjectVersion $document): bool
 | 
			
		||||
    {
 | 
			
		||||
        throw new \RuntimeException();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -99,3 +99,30 @@ CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE: Modifier un document
 | 
			
		||||
entity_display_title:
 | 
			
		||||
    Document (n°%doc%): "Document (n°%doc%)"
 | 
			
		||||
    Doc for evaluation (n°%eval%): Document de l'évaluation n°%eval%
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# SIGNATURES
 | 
			
		||||
 | 
			
		||||
signatures:
 | 
			
		||||
    yes: Oui
 | 
			
		||||
    are_you_sure: Êtes-vous sûr·e?
 | 
			
		||||
    you_are_going_to_sign: Vous allez signer le document
 | 
			
		||||
    signature_confirmation: Confirmation de la signature
 | 
			
		||||
    sign: Signer
 | 
			
		||||
    choose_another_signature: Choisir une autre zone
 | 
			
		||||
    cancel: Annuler
 | 
			
		||||
    last_sign_zone: Zone de signature précédente
 | 
			
		||||
    next_sign_zone: Zone de signature suivante
 | 
			
		||||
    add_sign_zone: Ajouter une zone de signature
 | 
			
		||||
    click_on_document: Cliquer sur le document
 | 
			
		||||
    last_zone: Zone précédente
 | 
			
		||||
    next_zone: Zone suivante
 | 
			
		||||
    add_zone: Ajouter une zone
 | 
			
		||||
    another_zone: Autre zone
 | 
			
		||||
    electronic_signature_in_progress: Signature électronique en cours...
 | 
			
		||||
    loading: Chargement...
 | 
			
		||||
    remove_sign_zone: Enlever la zone
 | 
			
		||||
    return: Retour
 | 
			
		||||
    see_all_pages: Voir toutes les pages
 | 
			
		||||
    all_pages: Toutes les pages
 | 
			
		||||
    go_to_signature_unique: Aller à la zone de signature
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,5 @@
 | 
			
		||||
#events
 | 
			
		||||
Name: Nom
 | 
			
		||||
Label: Nom
 | 
			
		||||
Date: Date
 | 
			
		||||
Event type : Type d'événement
 | 
			
		||||
See: Voir
 | 
			
		||||
Event: Événement
 | 
			
		||||
Events: Événements
 | 
			
		||||
'Event : %label%': Événement "%label%"
 | 
			
		||||
@@ -123,7 +119,6 @@ Role: Rôles
 | 
			
		||||
Role creation: Nouveau rôle
 | 
			
		||||
Role edit: Modifier un rôle
 | 
			
		||||
 | 
			
		||||
'': ''
 | 
			
		||||
xlsx: xlsx
 | 
			
		||||
ods: ods
 | 
			
		||||
csv: csv
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,6 @@ abstract class AbstractCRUDController extends AbstractController
 | 
			
		||||
            parent::getSubscribedServices(),
 | 
			
		||||
            [
 | 
			
		||||
                'chill_main.paginator_factory' => PaginatorFactory::class,
 | 
			
		||||
                ManagerRegistry::class => ManagerRegistry::class,
 | 
			
		||||
                'translator' => TranslatorInterface::class,
 | 
			
		||||
                AuthorizationHelper::class => AuthorizationHelper::class,
 | 
			
		||||
                EventDispatcherInterface::class => EventDispatcherInterface::class,
 | 
			
		||||
@@ -213,7 +212,7 @@ abstract class AbstractCRUDController extends AbstractController
 | 
			
		||||
 | 
			
		||||
    protected function getManagerRegistry(): ManagerRegistry
 | 
			
		||||
    {
 | 
			
		||||
        return $this->container->get(ManagerRegistry::class);
 | 
			
		||||
        return $this->container->get('doctrine');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -226,7 +225,7 @@ abstract class AbstractCRUDController extends AbstractController
 | 
			
		||||
 | 
			
		||||
    protected function getValidator(): ValidatorInterface
 | 
			
		||||
    {
 | 
			
		||||
        return $this->get('validator');
 | 
			
		||||
        return $this->container->get('validator');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ use Symfony\Component\Form\AbstractType;
 | 
			
		||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
 | 
			
		||||
use Symfony\Component\Form\FormBuilderInterface;
 | 
			
		||||
use Symfony\Component\OptionsResolver\OptionsResolver;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 | 
			
		||||
 | 
			
		||||
class ExportType extends AbstractType
 | 
			
		||||
{
 | 
			
		||||
@@ -29,7 +30,15 @@ class ExportType extends AbstractType
 | 
			
		||||
 | 
			
		||||
    final public const PICK_FORMATTER_KEY = 'pick_formatter';
 | 
			
		||||
 | 
			
		||||
    public function __construct(private readonly ExportManager $exportManager, private readonly SortExportElement $sortExportElement) {}
 | 
			
		||||
    private array $personFieldsConfig;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private readonly ExportManager $exportManager,
 | 
			
		||||
        private readonly SortExportElement $sortExportElement,
 | 
			
		||||
        protected ParameterBagInterface $parameterBag,
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->personFieldsConfig = $parameterBag->get('chill_person.person_fields');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildForm(FormBuilderInterface $builder, array $options)
 | 
			
		||||
    {
 | 
			
		||||
@@ -77,6 +86,17 @@ class ExportType extends AbstractType
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            foreach ($aggregators as $alias => $aggregator) {
 | 
			
		||||
                /*
 | 
			
		||||
                 * eventually mask aggregator
 | 
			
		||||
                 */
 | 
			
		||||
                if (str_starts_with((string) $alias, 'person_') and str_ends_with((string) $alias, '_aggregator')) {
 | 
			
		||||
                    $field = preg_replace(['/person_/', '/_aggregator/'], '', (string) $alias);
 | 
			
		||||
                    if (array_key_exists($field, $this->personFieldsConfig) and 'visible' !== $this->personFieldsConfig[$field]) {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                $aggregatorBuilder->add($alias, AggregatorType::class, [
 | 
			
		||||
                    'aggregator_alias' => $alias,
 | 
			
		||||
                    'export_manager' => $this->exportManager,
 | 
			
		||||
 
 | 
			
		||||
@@ -75,8 +75,8 @@ final class UserGroupRepository implements UserGroupRepositoryInterface, LocaleA
 | 
			
		||||
            ->setWhereClauses('
 | 
			
		||||
                ug.active AND (
 | 
			
		||||
                SIMILARITY(LOWER(UNACCENT(?)), ug.label->>?) > 0.15
 | 
			
		||||
                OR ug.label->>? LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\')
 | 
			
		||||
            ', [$pattern, $lang, $pattern, $lang]);
 | 
			
		||||
                OR LOWER(UNACCENT(ug.label->>?)) LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\')
 | 
			
		||||
            ', [$pattern, $lang, $lang, $pattern]);
 | 
			
		||||
 | 
			
		||||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,8 @@
 | 
			
		||||
 | 
			
		||||
@import './scss/hover.scss';
 | 
			
		||||
 | 
			
		||||
@import './scss/comment-editor.scss';
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *    BASE LAYOUT POSITION
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
.comment-container {
 | 
			
		||||
    margin-top: 1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.toggle-button {
 | 
			
		||||
    background-color: white;
 | 
			
		||||
    font-size: .8rem;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: -10px;
 | 
			
		||||
    left: 20px;
 | 
			
		||||
    padding: 2px 6px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
    transition: left 0.1s ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.rich-editor-active .toggle-button {
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.editor-wrapper textarea {
 | 
			
		||||
    resize: vertical;
 | 
			
		||||
    min-height: 100px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.editor-container {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.editor-wrapper {
 | 
			
		||||
    position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hidden-textarea {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
@@ -25,7 +25,34 @@ div.flex-table {
 | 
			
		||||
            div.item-col:last-child {
 | 
			
		||||
                display: flex;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            div.item-two-col-grid {
 | 
			
		||||
                display: grid;
 | 
			
		||||
                width: 100%;
 | 
			
		||||
                justify-content: stretch;
 | 
			
		||||
 | 
			
		||||
                @include media-breakpoint-up(lg) {
 | 
			
		||||
                    grid-template-areas:
 | 
			
		||||
                        "title aside";
 | 
			
		||||
                    grid-template-columns: 1fr minmax(8rem, 1fr);
 | 
			
		||||
                    column-gap: 0.5em;
 | 
			
		||||
                }
 | 
			
		||||
                @include media-breakpoint-down(lg) {
 | 
			
		||||
                    grid-template-areas:
 | 
			
		||||
                        "aside"
 | 
			
		||||
                        "title";
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                & > div.title {
 | 
			
		||||
                    grid-area: title;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                & > div.aside {
 | 
			
		||||
                    grid-area: aside;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    h2, h3, h4, dl, p {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,32 @@
 | 
			
		||||
import ClassicEditorBase from "@ckeditor/ckeditor5-editor-classic/src/classiceditor";
 | 
			
		||||
import EssentialsPlugin from "@ckeditor/ckeditor5-essentials/src/essentials";
 | 
			
		||||
import MarkdownPlugin from "@ckeditor/ckeditor5-markdown-gfm/src/markdown";
 | 
			
		||||
import BoldPlugin from "@ckeditor/ckeditor5-basic-styles/src/bold";
 | 
			
		||||
import ItalicPlugin from "@ckeditor/ckeditor5-basic-styles/src/italic";
 | 
			
		||||
import BlockQuotePlugin from "@ckeditor/ckeditor5-block-quote/src/blockquote";
 | 
			
		||||
import HeadingPlugin from "@ckeditor/ckeditor5-heading/src/heading";
 | 
			
		||||
import LinkPlugin from "@ckeditor/ckeditor5-link/src/link";
 | 
			
		||||
import ListPlugin from "@ckeditor/ckeditor5-list/src/list";
 | 
			
		||||
import ParagraphPlugin from "@ckeditor/ckeditor5-paragraph/src/paragraph";
 | 
			
		||||
import {
 | 
			
		||||
    Essentials,
 | 
			
		||||
    Bold,
 | 
			
		||||
    Italic,
 | 
			
		||||
    Paragraph,
 | 
			
		||||
    Markdown,
 | 
			
		||||
    BlockQuote,
 | 
			
		||||
    Heading,
 | 
			
		||||
    Link,
 | 
			
		||||
    List,
 | 
			
		||||
} from 'ckeditor5';
 | 
			
		||||
import coreTranslations from 'ckeditor5/translations/fr.js';
 | 
			
		||||
 | 
			
		||||
import 'ckeditor5/ckeditor5.css';
 | 
			
		||||
 | 
			
		||||
import "./index.scss";
 | 
			
		||||
 | 
			
		||||
export default class ClassicEditor extends ClassicEditorBase {}
 | 
			
		||||
 | 
			
		||||
ClassicEditor.builtinPlugins = [
 | 
			
		||||
    EssentialsPlugin,
 | 
			
		||||
    MarkdownPlugin,
 | 
			
		||||
    BoldPlugin,
 | 
			
		||||
    ItalicPlugin,
 | 
			
		||||
    BlockQuotePlugin,
 | 
			
		||||
    HeadingPlugin,
 | 
			
		||||
    LinkPlugin,
 | 
			
		||||
    ListPlugin,
 | 
			
		||||
    ParagraphPlugin,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
ClassicEditor.defaultConfig = {
 | 
			
		||||
export default {
 | 
			
		||||
    plugins: [
 | 
			
		||||
        Essentials,
 | 
			
		||||
        Markdown,
 | 
			
		||||
        Bold,
 | 
			
		||||
        Italic,
 | 
			
		||||
        BlockQuote,
 | 
			
		||||
        Heading,
 | 
			
		||||
        Link,
 | 
			
		||||
        List,
 | 
			
		||||
        Paragraph,
 | 
			
		||||
    ],
 | 
			
		||||
    toolbar: {
 | 
			
		||||
        items: [
 | 
			
		||||
            "heading",
 | 
			
		||||
@@ -39,5 +41,8 @@ ClassicEditor.defaultConfig = {
 | 
			
		||||
            "redo",
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    language: "fr",
 | 
			
		||||
};
 | 
			
		||||
    translations: [
 | 
			
		||||
        coreTranslations
 | 
			
		||||
    ],
 | 
			
		||||
    licenseKey: "GPL",
 | 
			
		||||
} ;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,23 @@
 | 
			
		||||
import ClassicEditor from "./editor_config";
 | 
			
		||||
import App from "../../vuejs/CommentEditor/App.vue"
 | 
			
		||||
import { createApp, reactive } from "vue";
 | 
			
		||||
 | 
			
		||||
const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
 | 
			
		||||
    document.querySelectorAll("textarea[ckeditor]");
 | 
			
		||||
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
 | 
			
		||||
    ClassicEditor.create(field)
 | 
			
		||||
        .then((editor) => {
 | 
			
		||||
            //console.log( 'CkEditor was initialized', editor );
 | 
			
		||||
        })
 | 
			
		||||
        .catch((error) => {
 | 
			
		||||
            console.error(error.stack);
 | 
			
		||||
        });
 | 
			
		||||
    document.querySelectorAll("[id^='comment-app']");
 | 
			
		||||
 | 
			
		||||
const globalState = reactive({
 | 
			
		||||
    isSimple: localStorage.getItem('editorMode') === 'simple'
 | 
			
		||||
});
 | 
			
		||||
window.addEventListener('storage', () => {
 | 
			
		||||
    globalState.isSimple = localStorage.getItem('editorMode') === 'simple';
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
 | 
			
		||||
    const app = createApp(App,{
 | 
			
		||||
        fieldName: field.dataset.fieldName,
 | 
			
		||||
        template: `<app></app>`
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    app.provide('globalState', globalState)
 | 
			
		||||
        .component("app", App)
 | 
			
		||||
        .mount(field);
 | 
			
		||||
});
 | 
			
		||||
//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,10 @@
 | 
			
		||||
import { createApp } from "vue";
 | 
			
		||||
import NotificationReadToggle from "ChillMainAssets/vuejs/_components/Notification/NotificationReadToggle.vue";
 | 
			
		||||
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
 | 
			
		||||
import NotificationReadAllToggle from "ChillMainAssets/vuejs/_components/Notification/NotificationReadAllToggle.vue";
 | 
			
		||||
 | 
			
		||||
const i18n = _createI18n({});
 | 
			
		||||
 | 
			
		||||
window.addEventListener("DOMContentLoaded", function (e) {
 | 
			
		||||
window.addEventListener("DOMContentLoaded", function () {
 | 
			
		||||
  document
 | 
			
		||||
    .querySelectorAll(".notification_toggle_read_status")
 | 
			
		||||
    .forEach(function (el, i) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,10 @@ let appsPerInput = new Map();
 | 
			
		||||
 | 
			
		||||
function loadDynamicPicker(element) {
 | 
			
		||||
  let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
 | 
			
		||||
  let suggested;
 | 
			
		||||
  let as_id;
 | 
			
		||||
  let submit_on_adding_new_entity;
 | 
			
		||||
  let label;
 | 
			
		||||
 | 
			
		||||
  apps.forEach(function (el) {
 | 
			
		||||
    const isMultiple = parseInt(el.dataset.multiple) === 1,
 | 
			
		||||
@@ -22,12 +26,12 @@ function loadDynamicPicker(element) {
 | 
			
		||||
        ? JSON.parse(input.value)
 | 
			
		||||
        : input.value === "[]" || input.value === ""
 | 
			
		||||
          ? null
 | 
			
		||||
          : [JSON.parse(input.value)];
 | 
			
		||||
    (suggested = JSON.parse(el.dataset.suggested)),
 | 
			
		||||
      (as_id = parseInt(el.dataset.asId) === 1),
 | 
			
		||||
      (submit_on_adding_new_entity =
 | 
			
		||||
        parseInt(el.dataset.submitOnAddingNewEntity) === 1);
 | 
			
		||||
    label = el.dataset.label;
 | 
			
		||||
          : [JSON.parse(input.value)],
 | 
			
		||||
      suggested = JSON.parse(el.dataset.suggested),
 | 
			
		||||
      as_id = parseInt(el.dataset.asId) === 1,
 | 
			
		||||
      submit_on_adding_new_entity =
 | 
			
		||||
        parseInt(el.dataset.submitOnAddingNewEntity) === 1,
 | 
			
		||||
      label = el.dataset.label;
 | 
			
		||||
 | 
			
		||||
    if (!isMultiple) {
 | 
			
		||||
      if (input.value === "[]") {
 | 
			
		||||
@@ -173,7 +177,7 @@ document.addEventListener("pick-entity-type-action", function (e) {
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
document.addEventListener("DOMContentLoaded", function (e) {
 | 
			
		||||
document.addEventListener("DOMContentLoaded", function () {
 | 
			
		||||
  loadDynamicPicker(document);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
import { createApp } from "vue";
 | 
			
		||||
import OpenWopiLink from "ChillMainAssets/vuejs/_components/OpenWopiLink";
 | 
			
		||||
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
 | 
			
		||||
 | 
			
		||||
const i18n = _createI18n({});
 | 
			
		||||
 | 
			
		||||
//TODO move to chillDocStore or ChillWopi
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
tags to load module:
 | 
			
		||||
 | 
			
		||||
<span data-module="wopi-link"
 | 
			
		||||
    data-wopi-url="{{ path('chill_wopi_file_edit', {'fileId': document.uuid}) }}"
 | 
			
		||||
    data-doc-type="{{ document.type|e('html_attr') }}"
 | 
			
		||||
    data-options="{{ options|json_encode }}"
 | 
			
		||||
        ></span>
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
window.addEventListener("DOMContentLoaded", function (e) {
 | 
			
		||||
  document
 | 
			
		||||
    .querySelectorAll('span[data-module="wopi-link"]')
 | 
			
		||||
    .forEach(function (el) {
 | 
			
		||||
      createApp({
 | 
			
		||||
        template:
 | 
			
		||||
          '<open-wopi-link :wopiUrl="wopiUrl" :type="type" :options="options"></open-wopi-link>',
 | 
			
		||||
        components: {
 | 
			
		||||
          OpenWopiLink,
 | 
			
		||||
        },
 | 
			
		||||
        data() {
 | 
			
		||||
          return {
 | 
			
		||||
            wopiUrl: el.dataset.wopiUrl,
 | 
			
		||||
            type: el.dataset.docType,
 | 
			
		||||
            options:
 | 
			
		||||
              el.dataset.options !== "null"
 | 
			
		||||
                ? JSON.parse(el.dataset.options)
 | 
			
		||||
                : {},
 | 
			
		||||
          };
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
        .use(i18n)
 | 
			
		||||
        .mount(el);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <div>
 | 
			
		||||
            <comment-editor
 | 
			
		||||
                :isSimple="globalState.isSimple"
 | 
			
		||||
                :fieldName="fieldName"
 | 
			
		||||
                @toggle="toggleEditorMode"
 | 
			
		||||
                ></comment-editor>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { defineComponent, inject } from 'vue';
 | 
			
		||||
import CommentEditor from "../CommentEditor/component/CommentEditor.vue";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
    name: "App",
 | 
			
		||||
    components: { CommentEditor },
 | 
			
		||||
    props: {
 | 
			
		||||
        fieldName: String
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
        const globalState = inject('globalState');
 | 
			
		||||
        const toggleEditorMode = () => {
 | 
			
		||||
            globalState.isSimple = !globalState.isSimple;
 | 
			
		||||
            localStorage.setItem('editorMode', globalState.isSimple ? 'simple' : 'rich');
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            globalState,
 | 
			
		||||
            toggleEditorMode,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div :class="{'editor-container': true, 'rich-editor-active': !isSimple}">
 | 
			
		||||
        <div v-if="!isSimple" class="editor-wrapper">
 | 
			
		||||
            <ckeditor
 | 
			
		||||
                :name="fieldName"
 | 
			
		||||
                :editor="classicEditor"
 | 
			
		||||
                :config="editorConfig"
 | 
			
		||||
                v-model.lazy="content"
 | 
			
		||||
                tag-name="textarea"
 | 
			
		||||
            />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div v-else class="editor-wrapper">
 | 
			
		||||
            <textarea
 | 
			
		||||
                v-model.lazy="content"
 | 
			
		||||
                :name="fieldName"
 | 
			
		||||
                class="form-control"
 | 
			
		||||
            ></textarea>
 | 
			
		||||
        </div>
 | 
			
		||||
        <a @click="toggleSimpleEditor" class="toggle-button">{{ isSimple ? "rich" : "simple" }}</a>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, ref, computed, toRefs } from 'vue';
 | 
			
		||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
 | 
			
		||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
 | 
			
		||||
import { ClassicEditor } from "ckeditor5";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
    name: "CommentEditor",
 | 
			
		||||
    components: {
 | 
			
		||||
        ckeditor: Ckeditor,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        isSimple: Boolean,
 | 
			
		||||
        fieldName: String,
 | 
			
		||||
    },
 | 
			
		||||
    setup(props, { emit }) {
 | 
			
		||||
        const { isSimple } = toRefs(props);
 | 
			
		||||
        const content = ref("");
 | 
			
		||||
        const classicEditor = ClassicEditor;
 | 
			
		||||
        const editorConfig = classicEditorConfig;
 | 
			
		||||
 | 
			
		||||
        const toggleSimpleEditor = () => {
 | 
			
		||||
            emit("toggle");
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            isSimple,
 | 
			
		||||
            content,
 | 
			
		||||
            classicEditor,
 | 
			
		||||
            editorConfig,
 | 
			
		||||
            toggleSimpleEditor,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
import {personMessages} from "ChillPersonAssets/vuejs/_js/i18n";
 | 
			
		||||
import {calendarUserSelectorMessages} from "ChillCalendarAssets/vuejs/_components/CalendarUserSelector/js/i18n";
 | 
			
		||||
import {activityMessages} from "ChillActivityAssets/vuejs/Activity/i18n";
 | 
			
		||||
 | 
			
		||||
const appMessages = {
 | 
			
		||||
  fr: {
 | 
			
		||||
    mode: {
 | 
			
		||||
      simple: "Editeur simple",
 | 
			
		||||
      rich: "Editeur riche"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export { appMessages };
 | 
			
		||||
@@ -45,6 +45,10 @@ const onPickGenericDoc = ({
 | 
			
		||||
}) => {
 | 
			
		||||
    emit("pickGenericDoc", { genericDoc });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onRemoveAttachment = (payload: { attachment: WorkflowAttachment }) => {
 | 
			
		||||
    emit("removeAttachment", payload);
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
@@ -56,7 +60,7 @@ const onPickGenericDoc = ({
 | 
			
		||||
    ></pick-generic-doc-modal>
 | 
			
		||||
    <attachment-list
 | 
			
		||||
        :attachments="props.attachments"
 | 
			
		||||
        @removeAttachment="(payload) => emit('removeAttachment', payload)"
 | 
			
		||||
        @removeAttachment="onRemoveAttachment"
 | 
			
		||||
    ></attachment-list>
 | 
			
		||||
    <ul class="record_actions">
 | 
			
		||||
        <li>
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,14 @@ const placeTrans = (str: string): string => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onPickDocument = (payload: {
 | 
			
		||||
    genericDoc: GenericDocForAccompanyingPeriod;
 | 
			
		||||
}) => emit("pickGenericDoc", payload);
 | 
			
		||||
 | 
			
		||||
const onRemoveGenericDoc = (payload: {
 | 
			
		||||
    genericDoc: GenericDocForAccompanyingPeriod;
 | 
			
		||||
}) => emit("removeGenericDoc", payload);
 | 
			
		||||
 | 
			
		||||
const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
 | 
			
		||||
    if (false === loaded.value) {
 | 
			
		||||
        return [];
 | 
			
		||||
@@ -245,10 +253,8 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
 | 
			
		||||
                :accompanying-period-id="accompanyingPeriodId"
 | 
			
		||||
                :genericDoc="g"
 | 
			
		||||
                :is-picked="isPicked(g)"
 | 
			
		||||
                @pickGenericDoc="(payload) => emit('pickGenericDoc', payload)"
 | 
			
		||||
                @removeGenericDoc="
 | 
			
		||||
                    (payload) => emit('removeGenericDoc', payload)
 | 
			
		||||
                "
 | 
			
		||||
                @pickGenericDoc="onPickDocument"
 | 
			
		||||
                @removeGenericDoc="onRemoveGenericDoc"
 | 
			
		||||
            ></pick-generic-doc-item>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div v-else class="text-center chill-no-data-statement">
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,8 @@ const clickOnAddButton = () => {
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.item-bloc {
 | 
			
		||||
    &.isPicked {
 | 
			
		||||
        background: linear-gradient(
 | 
			
		||||
        background:
 | 
			
		||||
            linear-gradient(
 | 
			
		||||
                180deg,
 | 
			
		||||
                rgba(25, 135, 84, 1) 0px,
 | 
			
		||||
                rgba(25, 135, 84, 0) 9px
 | 
			
		||||
 
 | 
			
		||||
@@ -1,61 +1,66 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <span v-if="entity.type === 'person'" class="badge rounded-pill bg-person">
 | 
			
		||||
        {{ $t("person") }}
 | 
			
		||||
    <span
 | 
			
		||||
        v-if="props.entity.type === 'person'"
 | 
			
		||||
        class="badge rounded-pill bg-person"
 | 
			
		||||
    >
 | 
			
		||||
        {{ trans(PERSON) }}
 | 
			
		||||
    </span>
 | 
			
		||||
 | 
			
		||||
    <span
 | 
			
		||||
        v-if="entity.type === 'thirdparty'"
 | 
			
		||||
        v-if="props.entity.type === 'thirdparty'"
 | 
			
		||||
        class="badge rounded-pill bg-thirdparty"
 | 
			
		||||
    >
 | 
			
		||||
        <template v-if="options.displayLong !== true">
 | 
			
		||||
            {{ $t("thirdparty.thirdparty") }}
 | 
			
		||||
        <template v-if="props.options.displayLong !== true">
 | 
			
		||||
            {{ trans(THIRDPARTY) }}
 | 
			
		||||
        </template>
 | 
			
		||||
 | 
			
		||||
        <i class="fa fa-fw fa-user" v-if="entity.kind === 'child'" />
 | 
			
		||||
        <i class="fa fa-fw fa-user" v-if="props.entity.kind === 'child'" />
 | 
			
		||||
        <i
 | 
			
		||||
            class="fa fa-fw fa-hospital-o"
 | 
			
		||||
            v-else-if="entity.kind === 'company'"
 | 
			
		||||
            v-else-if="props.entity.kind === 'company'"
 | 
			
		||||
        />
 | 
			
		||||
        <i class="fa fa-fw fa-user-md" v-else />
 | 
			
		||||
 | 
			
		||||
        <template v-if="options.displayLong === true">
 | 
			
		||||
            <span v-if="entity.kind === 'child'">{{
 | 
			
		||||
                $t("thirdparty.child")
 | 
			
		||||
        <template v-if="props.options.displayLong === true">
 | 
			
		||||
            <span v-if="props.entity.kind === 'child'">{{
 | 
			
		||||
                trans(THIRDPARTY_CONTACT_OF)
 | 
			
		||||
            }}</span>
 | 
			
		||||
            <span v-else-if="entity.kind === 'company'">{{
 | 
			
		||||
                $t("thirdparty.company")
 | 
			
		||||
            <span v-else-if="props.entity.kind === 'company'">{{
 | 
			
		||||
                trans(THIRDPARTY_A_COMPANY)
 | 
			
		||||
            }}</span>
 | 
			
		||||
            <span v-else>{{ $t("thirdparty.contact") }}</span>
 | 
			
		||||
            <span v-else>{{ trans(THIRDPARTY_A_CONTACT) }}</span>
 | 
			
		||||
        </template>
 | 
			
		||||
    </span>
 | 
			
		||||
 | 
			
		||||
    <span v-if="entity.type === 'user'" class="badge rounded-pill bg-user">
 | 
			
		||||
        {{ $t("user") }}
 | 
			
		||||
    <span
 | 
			
		||||
        v-if="props.entity.type === 'user'"
 | 
			
		||||
        class="badge rounded-pill bg-user"
 | 
			
		||||
    >
 | 
			
		||||
        {{ trans(ACCEPTED_USERS) }}
 | 
			
		||||
    </span>
 | 
			
		||||
 | 
			
		||||
    <span v-if="entity.type === 'household'" class="badge rounded-pill bg-user">
 | 
			
		||||
        {{ $t("household") }}
 | 
			
		||||
    <span
 | 
			
		||||
        v-if="props.entity.type === 'household'"
 | 
			
		||||
        class="badge rounded-pill bg-user"
 | 
			
		||||
    >
 | 
			
		||||
        {{ trans(HOUSEHOLD) }}
 | 
			
		||||
    </span>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    name: "BadgeEntity",
 | 
			
		||||
    props: ["options", "entity"],
 | 
			
		||||
    i18n: {
 | 
			
		||||
        messages: {
 | 
			
		||||
            fr: {
 | 
			
		||||
                person: "Usager",
 | 
			
		||||
                thirdparty: {
 | 
			
		||||
                    thirdparty: "Tiers",
 | 
			
		||||
                    child: "Personne de contact",
 | 
			
		||||
                    company: "Personne morale",
 | 
			
		||||
                    contact: "Personne physique",
 | 
			
		||||
                },
 | 
			
		||||
                user: "TMS",
 | 
			
		||||
                household: "Ménage",
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
<script setup>
 | 
			
		||||
import {
 | 
			
		||||
    trans,
 | 
			
		||||
    HOUSEHOLD,
 | 
			
		||||
    ACCEPTED_USERS,
 | 
			
		||||
    THIRDPARTY_A_CONTACT,
 | 
			
		||||
    THIRDPARTY_CONTACT_OF,
 | 
			
		||||
    THIRDPARTY_A_COMPANY,
 | 
			
		||||
    PERSON,
 | 
			
		||||
    THIRDPARTY,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    options: Object,
 | 
			
		||||
    entity: Object,
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -66,13 +66,13 @@
 | 
			
		||||
        <div v-if="useDatePane === true" class="address-more">
 | 
			
		||||
            <div v-if="address.validFrom">
 | 
			
		||||
                <span class="validFrom">
 | 
			
		||||
                    <b>{{ $t("validFrom") }}</b
 | 
			
		||||
                    <b>{{ trans(ADDRESS_VALID_FROM) }}</b
 | 
			
		||||
                    >: {{ $d(address.validFrom.date) }}
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div v-if="address.validTo">
 | 
			
		||||
                <span class="validTo">
 | 
			
		||||
                    <b>{{ $t("validTo") }}</b
 | 
			
		||||
                    <b>{{ trans(ADDRESS_VALID_TO) }}</b
 | 
			
		||||
                    >: {{ $d(address.validTo.date) }}
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -83,6 +83,7 @@
 | 
			
		||||
<script>
 | 
			
		||||
import Confidential from "ChillMainAssets/vuejs/_components/Confidential.vue";
 | 
			
		||||
import AddressDetailsButton from "ChillMainAssets/vuejs/_components/AddressDetails/AddressDetailsButton.vue";
 | 
			
		||||
import { trans, ADDRESS_VALID_FROM, ADDRESS_VALID_TO } from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "AddressRenderBox",
 | 
			
		||||
@@ -107,6 +108,9 @@ export default {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
        return { trans, ADDRESS_VALID_FROM, ADDRESS_VALID_TO };
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        component() {
 | 
			
		||||
            return this.isMultiline === true ? "div" : "span";
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,8 @@
 | 
			
		||||
            v-if="!subscriberFinal"
 | 
			
		||||
            @click="subscribeTo('subscribe', 'final')"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-check fa-fw" />
 | 
			
		||||
            {{ $t("subscribe_final") }}
 | 
			
		||||
            <i class="fa fa-check fa-fw"></i>
 | 
			
		||||
            {{ trans(WORKFLOW_SUBSCRIBE_FINAL) }}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button
 | 
			
		||||
            class="btn btn-misc"
 | 
			
		||||
@@ -15,8 +15,8 @@
 | 
			
		||||
            v-if="subscriberFinal"
 | 
			
		||||
            @click="subscribeTo('unsubscribe', 'final')"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-times fa-fw" />
 | 
			
		||||
            {{ $t("unsubscribe_final") }}
 | 
			
		||||
            <i class="fa fa-times fa-fw"></i>
 | 
			
		||||
            {{ trans(WORKFLOW_UNSUBSCRIBE_FINAL) }}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button
 | 
			
		||||
            class="btn btn-misc"
 | 
			
		||||
@@ -24,8 +24,8 @@
 | 
			
		||||
            v-if="!subscriberStep"
 | 
			
		||||
            @click="subscribeTo('subscribe', 'step')"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-check fa-fw" />
 | 
			
		||||
            {{ $t("subscribe_all_steps") }}
 | 
			
		||||
            <i class="fa fa-check fa-fw"></i>
 | 
			
		||||
            {{ trans(WORKFLOW_SUBSCRIBE_ALL_STEPS) }}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button
 | 
			
		||||
            class="btn btn-misc"
 | 
			
		||||
@@ -33,94 +33,55 @@
 | 
			
		||||
            v-if="subscriberStep"
 | 
			
		||||
            @click="subscribeTo('unsubscribe', 'step')"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-times fa-fw" />
 | 
			
		||||
            {{ $t("unsubscribe_all_steps") }}
 | 
			
		||||
            <i class="fa fa-times fa-fw"></i>
 | 
			
		||||
            {{ trans(WORKFLOW_UNSUBSCRIBE_ALL_STEPS) }}
 | 
			
		||||
        </button>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
<script setup>
 | 
			
		||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
 | 
			
		||||
import { defineProps, defineEmits } from "vue";
 | 
			
		||||
import {
 | 
			
		||||
    trans,
 | 
			
		||||
    WORKFLOW_SUBSCRIBE_FINAL,
 | 
			
		||||
    WORKFLOW_UNSUBSCRIBE_FINAL,
 | 
			
		||||
    WORKFLOW_SUBSCRIBE_ALL_STEPS,
 | 
			
		||||
    WORKFLOW_UNSUBSCRIBE_ALL_STEPS,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    entityWorkflowId: {
 | 
			
		||||
        type: Number,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
        entityWorkflowId: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        subscriberStep: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        subscriberFinal: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
    subscriberStep: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    emits: ["subscriptionUpdated"],
 | 
			
		||||
    methods: {
 | 
			
		||||
        subscribeTo(step, to) {
 | 
			
		||||
            let params = new URLSearchParams();
 | 
			
		||||
            params.set("subscribe", to);
 | 
			
		||||
    subscriberFinal: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
            const url =
 | 
			
		||||
                `/api/1.0/main/workflow/${this.entityWorkflowId}/${step}?` +
 | 
			
		||||
                params.toString();
 | 
			
		||||
//methods
 | 
			
		||||
const subscribeTo = (step, to) => {
 | 
			
		||||
    let params = new URLSearchParams();
 | 
			
		||||
    params.set("subscribe", to);
 | 
			
		||||
 | 
			
		||||
            makeFetch("POST", url).then((response) => {
 | 
			
		||||
                this.$emit("subscriptionUpdated", response);
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    const url =
 | 
			
		||||
        `/api/1.0/main/workflow/${props.entityWorkflowId}/${step}?` +
 | 
			
		||||
        params.toString();
 | 
			
		||||
 | 
			
		||||
    makeFetch("POST", url).then((response) => {
 | 
			
		||||
        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>
 | 
			
		||||
*/
 | 
			
		||||
// emit
 | 
			
		||||
const emit = defineEmits(["subscriptionUpdated"]);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="flex-table workflow" id="workflow-list">
 | 
			
		||||
        <div
 | 
			
		||||
            v-for="(w, i) in workflows"
 | 
			
		||||
            v-for="(w, i) in props.workflows"
 | 
			
		||||
            :key="`workflow-${i}`"
 | 
			
		||||
            class="item-bloc"
 | 
			
		||||
        >
 | 
			
		||||
@@ -48,7 +48,7 @@
 | 
			
		||||
                <span
 | 
			
		||||
                    v-if="w.isOnHoldAtCurrentStep"
 | 
			
		||||
                    class="badge bg-success rounded-pill"
 | 
			
		||||
                    >{{ $t("on_hold") }}</span
 | 
			
		||||
                    >{{ trans(WORKFLOW_ON_HOLD) }}</span
 | 
			
		||||
                >
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
@@ -56,11 +56,11 @@
 | 
			
		||||
                <div class="item-col flex-grow-1">
 | 
			
		||||
                    <p v-if="isUserSubscribedToStep(w)">
 | 
			
		||||
                        <i class="fa fa-check fa-fw"></i>
 | 
			
		||||
                        {{ $t("you_subscribed_to_all_steps") }}
 | 
			
		||||
                        {{ trans(WORKFLOW_YOU_SUBSCRIBED_TO_ALL_STEPS) }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p v-if="isUserSubscribedToFinal(w)">
 | 
			
		||||
                        <i class="fa fa-check fa-fw"></i>
 | 
			
		||||
                        {{ $t("you_subscribed_to_final_step") }}
 | 
			
		||||
                        {{ trans(WORKFLOW_YOU_SUBSCRIBED_TO_FINAL_STEP) }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="item-col">
 | 
			
		||||
@@ -69,7 +69,7 @@
 | 
			
		||||
                            <a
 | 
			
		||||
                                :href="goToUrl(w)"
 | 
			
		||||
                                class="btn btn-sm btn-show"
 | 
			
		||||
                                :title="$t('action.show')"
 | 
			
		||||
                                :title="trans(SEE)"
 | 
			
		||||
                            ></a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
@@ -79,85 +79,65 @@
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
<script setup>
 | 
			
		||||
import Popover from "bootstrap/js/src/popover";
 | 
			
		||||
import { onMounted } from "vue";
 | 
			
		||||
import {
 | 
			
		||||
    trans,
 | 
			
		||||
    BY_USER,
 | 
			
		||||
    SEE,
 | 
			
		||||
    WORKFLOW_YOU_SUBSCRIBED_TO_ALL_STEPS,
 | 
			
		||||
    WORKFLOW_YOU_SUBSCRIBED_TO_FINAL_STEP,
 | 
			
		||||
    WORKFLOW_ON_HOLD,
 | 
			
		||||
    WORKFLOW_AT,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
const i18n = {
 | 
			
		||||
    messages: {
 | 
			
		||||
        fr: {
 | 
			
		||||
            you_subscribed_to_all_steps:
 | 
			
		||||
                "Vous recevrez une notification à chaque étape",
 | 
			
		||||
            you_subscribed_to_final_step:
 | 
			
		||||
                "Vous recevrez une notification à l'étape finale",
 | 
			
		||||
            by: "Par",
 | 
			
		||||
            at: "Le",
 | 
			
		||||
            on_hold: "En attente",
 | 
			
		||||
        },
 | 
			
		||||
// props
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    workflows: {
 | 
			
		||||
        type: Array,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// methods
 | 
			
		||||
const goToUrl = (w) => `/fr/main/workflow/${w.id}/show`;
 | 
			
		||||
const getPopTitle = (step) => {
 | 
			
		||||
    if (step.transitionPrevious != null) {
 | 
			
		||||
        //console.log(step.transitionPrevious.text);
 | 
			
		||||
        let freezed = step.isFreezed
 | 
			
		||||
            ? `<i class="fa fa-snowflake-o fa-sm me-1"></i>`
 | 
			
		||||
            : ``;
 | 
			
		||||
        return `${freezed}${step.transitionPrevious.text}`;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
const getPopContent = (step) => {
 | 
			
		||||
    if (step.transitionPrevious != null) {
 | 
			
		||||
        if (step.transitionPreviousBy !== null) {
 | 
			
		||||
            return `<ul class="small_in_title">
 | 
			
		||||
              <li><span class="item-key">${trans(BY_USER)} : </span><b>${step.transitionPreviousBy.text}</b></li>
 | 
			
		||||
              <li><span class="item-key">${trans(WORKFLOW_AT)} : </span><b>${formatDate(step.transitionPreviousAt.datetime)}</b></li>
 | 
			
		||||
              </ul>`;
 | 
			
		||||
        } else {
 | 
			
		||||
            return `<ul class="small_in_title">
 | 
			
		||||
                      <li><span class="item-key">${trans(WORKFLOW_AT)} : </span><b>${formatDate(step.transitionPreviousAt.datetime)}</b></li>
 | 
			
		||||
                  </ul>`;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
const formatDate = (datetime) =>
 | 
			
		||||
    datetime.split("T")[0] + " " + datetime.split("T")[1].substring(0, 5);
 | 
			
		||||
const isUserSubscribedToStep = () => false;
 | 
			
		||||
const isUserSubscribedToFinal = () => false;
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "ListWorkflow",
 | 
			
		||||
    i18n: i18n,
 | 
			
		||||
    props: {
 | 
			
		||||
        workflows: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        goToUrl(w) {
 | 
			
		||||
            return `/fr/main/workflow/${w.id}/show`;
 | 
			
		||||
        },
 | 
			
		||||
        getPopTitle(step) {
 | 
			
		||||
            if (step.transitionPrevious != null) {
 | 
			
		||||
                //console.log(step.transitionPrevious.text);
 | 
			
		||||
                let freezed = step.isFreezed
 | 
			
		||||
                    ? `<i class="fa fa-snowflake-o fa-sm me-1"></i>`
 | 
			
		||||
                    : ``;
 | 
			
		||||
                return `${freezed}${step.transitionPrevious.text}`;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        getPopContent(step) {
 | 
			
		||||
            if (step.transitionPrevious != null) {
 | 
			
		||||
                if (step.transitionPreviousBy !== null) {
 | 
			
		||||
                    return `<ul class="small_in_title">
 | 
			
		||||
                      <li><span class="item-key">${i18n.messages.fr.by} : </span><b>${step.transitionPreviousBy.text}</b></li>
 | 
			
		||||
                      <li><span class="item-key">${i18n.messages.fr.at} : </span><b>${this.formatDate(step.transitionPreviousAt.datetime)}</b></li>
 | 
			
		||||
                      </ul>`;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return `<ul class="small_in_title">
 | 
			
		||||
                      <li><span class="item-key">${i18n.messages.fr.at} : </span><b>${this.formatDate(step.transitionPreviousAt.datetime)}</b></li>
 | 
			
		||||
                      </ul>`;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        formatDate(datetime) {
 | 
			
		||||
            return (
 | 
			
		||||
                datetime.split("T")[0] +
 | 
			
		||||
                " " +
 | 
			
		||||
                datetime.split("T")[1].substring(0, 5)
 | 
			
		||||
            );
 | 
			
		||||
        },
 | 
			
		||||
        isUserSubscribedToStep(w) {
 | 
			
		||||
            // todo
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        isUserSubscribedToFinal(w) {
 | 
			
		||||
            // todo
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        const triggerList = [].slice.call(
 | 
			
		||||
            document.querySelectorAll('[data-bs-toggle="popover"]'),
 | 
			
		||||
        );
 | 
			
		||||
        const popoverList = triggerList.map(function (el) {
 | 
			
		||||
            //console.log('popover', el)
 | 
			
		||||
            return new Popover(el, {
 | 
			
		||||
                html: true,
 | 
			
		||||
            });
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
    const triggerList = [].slice.call(
 | 
			
		||||
        document.querySelectorAll('[data-bs-toggle="popover"]'),
 | 
			
		||||
    );
 | 
			
		||||
    triggerList.map(function (el) {
 | 
			
		||||
        return new Popover(el, {
 | 
			
		||||
            html: true,
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,24 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <pick-workflow
 | 
			
		||||
        :relatedEntityClass="this.relatedEntityClass"
 | 
			
		||||
        :relatedEntityId="this.relatedEntityId"
 | 
			
		||||
        :workflowsAvailables="workflowsAvailables"
 | 
			
		||||
        :preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
 | 
			
		||||
        :goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
 | 
			
		||||
    <Pick-workflow
 | 
			
		||||
        :relatedEntityClass="props.relatedEntityClass"
 | 
			
		||||
        :relatedEntityId="props.relatedEntityId"
 | 
			
		||||
        :workflowsAvailables="props.workflowsAvailables"
 | 
			
		||||
        :preventDefaultMoveToGenerate="props.preventDefaultMoveToGenerate"
 | 
			
		||||
        :goToGenerateWorkflowPayload="props.goToGenerateWorkflowPayload"
 | 
			
		||||
        :countExistingWorkflows="countWorkflows"
 | 
			
		||||
        :embedded-within-list-modal="false"
 | 
			
		||||
        @go-to-generate-workflow="goToGenerateWorkflow"
 | 
			
		||||
        @click-open-list="openModal"
 | 
			
		||||
    ></pick-workflow>
 | 
			
		||||
    ></Pick-workflow>
 | 
			
		||||
 | 
			
		||||
    <teleport to="body">
 | 
			
		||||
        <modal
 | 
			
		||||
        <Modal
 | 
			
		||||
            v-if="modal.showModal"
 | 
			
		||||
            :modalDialogClass="modal.modalDialogClass"
 | 
			
		||||
            @close="modal.showModal = false"
 | 
			
		||||
        >
 | 
			
		||||
            <template v-slot:header>
 | 
			
		||||
                <h2 class="modal-title">{{ $t("workflow_list") }}</h2>
 | 
			
		||||
                <h2 class="modal-title">{{ trans(WORKFLOW_LIST) }}</h2>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template v-slot:body>
 | 
			
		||||
@@ -27,103 +28,80 @@
 | 
			
		||||
            <template v-slot:footer>
 | 
			
		||||
                <pick-workflow
 | 
			
		||||
                    v-if="allowCreate"
 | 
			
		||||
                    :relatedEntityClass="this.relatedEntityClass"
 | 
			
		||||
                    :relatedEntityId="this.relatedEntityId"
 | 
			
		||||
                    :workflowsAvailables="workflowsAvailables"
 | 
			
		||||
                    :relatedEntityClass="props.relatedEntityClass"
 | 
			
		||||
                    :relatedEntityId="props.relatedEntityId"
 | 
			
		||||
                    :workflowsAvailables="props.workflowsAvailables"
 | 
			
		||||
                    :preventDefaultMoveToGenerate="
 | 
			
		||||
                        this.$props.preventDefaultMoveToGenerate
 | 
			
		||||
                        props.preventDefaultMoveToGenerate
 | 
			
		||||
                    "
 | 
			
		||||
                    :goToGenerateWorkflowPayload="
 | 
			
		||||
                        this.goToGenerateWorkflowPayload
 | 
			
		||||
                        props.goToGenerateWorkflowPayload
 | 
			
		||||
                    "
 | 
			
		||||
                    :countExistingWorkflows="countWorkflows"
 | 
			
		||||
                    :embedded-within-list-modal="true"
 | 
			
		||||
                    @go-to-generate-workflow="this.goToGenerateWorkflow"
 | 
			
		||||
                    @go-to-generate-workflow="goToGenerateWorkflow"
 | 
			
		||||
                ></pick-workflow>
 | 
			
		||||
            </template>
 | 
			
		||||
        </modal>
 | 
			
		||||
        </Modal>
 | 
			
		||||
    </teleport>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref, computed, defineProps, defineEmits } from "vue";
 | 
			
		||||
import Modal from "ChillMainAssets/vuejs/_components/Modal";
 | 
			
		||||
import PickWorkflow from "ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue";
 | 
			
		||||
import ListWorkflowVue from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflow.vue";
 | 
			
		||||
import { trans, WORKFLOW_LIST } from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "ListWorkflowModal",
 | 
			
		||||
    components: {
 | 
			
		||||
        Modal,
 | 
			
		||||
        PickWorkflow,
 | 
			
		||||
        ListWorkflowVue,
 | 
			
		||||
// Define props
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    workflows: {
 | 
			
		||||
        type: Array,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    emits: ["goToGenerateWorkflow"],
 | 
			
		||||
    props: {
 | 
			
		||||
        workflows: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        allowCreate: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        relatedEntityClass: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        relatedEntityId: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: false,
 | 
			
		||||
        },
 | 
			
		||||
        workflowsAvailables: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        preventDefaultMoveToGenerate: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: false,
 | 
			
		||||
            default: false,
 | 
			
		||||
        },
 | 
			
		||||
        goToGenerateWorkflowPayload: {
 | 
			
		||||
            required: false,
 | 
			
		||||
            default: {},
 | 
			
		||||
        },
 | 
			
		||||
    allowCreate: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            modal: {
 | 
			
		||||
                showModal: false,
 | 
			
		||||
                modalDialogClass: "modal-dialog-scrollable modal-xl",
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    relatedEntityClass: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        countWorkflows() {
 | 
			
		||||
            return this.workflows.length;
 | 
			
		||||
        },
 | 
			
		||||
        hasWorkflow() {
 | 
			
		||||
            return this.countWorkflows > 0;
 | 
			
		||||
        },
 | 
			
		||||
    relatedEntityId: {
 | 
			
		||||
        type: Number,
 | 
			
		||||
        required: false,
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        openModal() {
 | 
			
		||||
            this.modal.showModal = true;
 | 
			
		||||
        },
 | 
			
		||||
        goToGenerateWorkflow(data) {
 | 
			
		||||
            console.log("go to generate workflow intercepted", data);
 | 
			
		||||
            this.$emit("goToGenerateWorkflow", data);
 | 
			
		||||
        },
 | 
			
		||||
    workflowsAvailables: {
 | 
			
		||||
        type: Array,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    i18n: {
 | 
			
		||||
        messages: {
 | 
			
		||||
            fr: {
 | 
			
		||||
                workflow_list: "Liste des workflows associés",
 | 
			
		||||
                workflow: " workflow associé",
 | 
			
		||||
                workflows: " workflows associés",
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    preventDefaultMoveToGenerate: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: false,
 | 
			
		||||
        default: false,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
    goToGenerateWorkflowPayload: {
 | 
			
		||||
        required: false,
 | 
			
		||||
        default: () => ({}),
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Define emits
 | 
			
		||||
const emit = defineEmits(["goToGenerateWorkflow"]);
 | 
			
		||||
 | 
			
		||||
// Reactive data
 | 
			
		||||
const modal = ref({
 | 
			
		||||
    showModal: false,
 | 
			
		||||
    modalDialogClass: "modal-dialog-scrollable modal-xl",
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Computed properties
 | 
			
		||||
const countWorkflows = computed(() => props.workflows.length);
 | 
			
		||||
 | 
			
		||||
// Methods
 | 
			
		||||
const openModal = () => (modal.value.showModal = true);
 | 
			
		||||
 | 
			
		||||
const goToGenerateWorkflow = (data) => emit("goToGenerateWorkflow", data);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,28 +8,28 @@
 | 
			
		||||
                aria-modal="true"
 | 
			
		||||
                role="dialog"
 | 
			
		||||
            >
 | 
			
		||||
                <div class="modal-dialog" :class="modalDialogClass">
 | 
			
		||||
                <div class="modal-dialog" :class="props.modalDialogClass || {}">
 | 
			
		||||
                    <div class="modal-content">
 | 
			
		||||
                        <div class="modal-header">
 | 
			
		||||
                            <slot name="header" />
 | 
			
		||||
                            <button class="close btn" @click="$emit('close')">
 | 
			
		||||
                                <i class="fa fa-times" aria-hidden="true" />
 | 
			
		||||
                            <slot name="header"></slot>
 | 
			
		||||
                            <button class="close btn" @click="emits('close')">
 | 
			
		||||
                                <i class="fa fa-times" aria-hidden="true"></i>
 | 
			
		||||
                            </button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="modal-body">
 | 
			
		||||
                            <div class="body-head">
 | 
			
		||||
                                <slot name="body-head" />
 | 
			
		||||
                                <slot name="body-head"></slot>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <slot name="body" />
 | 
			
		||||
                            <slot name="body"></slot>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="modal-footer" v-if="!hideFooter">
 | 
			
		||||
                            <button
 | 
			
		||||
                                class="btn btn-cancel"
 | 
			
		||||
                                @click="$emit('close')"
 | 
			
		||||
                                @click="emits('close')"
 | 
			
		||||
                            >
 | 
			
		||||
                                {{ $t("action.close") }}
 | 
			
		||||
                                {{ trans(MODAL_ACTION_CLOSE) }}
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <slot name="footer" />
 | 
			
		||||
                            <slot name="footer"></slot>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -39,8 +39,7 @@
 | 
			
		||||
    </transition>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from "vue";
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
/*
 | 
			
		||||
 *    This Modal component is a mix between Vue3 modal implementation
 | 
			
		||||
 *    [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
 | 
			
		||||
@@ -50,22 +49,23 @@ import { defineComponent } from "vue";
 | 
			
		||||
 *    [+] using bootstrap css classes, the modal have a responsive behaviour,
 | 
			
		||||
 *    [+] modal design can be configured using css classes (size, scroll)
 | 
			
		||||
 */
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
    name: "Modal",
 | 
			
		||||
    props: {
 | 
			
		||||
        modalDialogClass: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: false,
 | 
			
		||||
            default: {},
 | 
			
		||||
        },
 | 
			
		||||
        hideFooter: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: false,
 | 
			
		||||
            default: false,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    emits: ["close"],
 | 
			
		||||
import { trans, MODAL_ACTION_CLOSE } from "translator";
 | 
			
		||||
import { defineProps } from "vue";
 | 
			
		||||
 | 
			
		||||
export interface ModalProps {
 | 
			
		||||
    modalDialogClass: object | null;
 | 
			
		||||
    hideFooter: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Define the props
 | 
			
		||||
const props = withDefaults(defineProps<ModalProps>(), {
 | 
			
		||||
    hideFooter: false,
 | 
			
		||||
    modalDialogClass: null,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emits = defineEmits<{
 | 
			
		||||
    close: [];
 | 
			
		||||
}>();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,12 @@
 | 
			
		||||
            class="btn"
 | 
			
		||||
            :class="overrideClass"
 | 
			
		||||
            type="button"
 | 
			
		||||
            :title="$t('markAsUnread')"
 | 
			
		||||
            :title="trans(NOTIFICATION_MARK_AS_UNREAD)"
 | 
			
		||||
            @click="markAsUnread"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-sm fa-envelope-o" />
 | 
			
		||||
            <span v-if="!buttonNoText" class="ps-2">
 | 
			
		||||
                {{ $t("markAsUnread") }}
 | 
			
		||||
            <i class="fa fa-sm fa-envelope-o"></i>
 | 
			
		||||
            <span v-if="!props.buttonNoText" class="ps-2">
 | 
			
		||||
                {{ trans(NOTIFICATION_MARK_AS_UNREAD) }}
 | 
			
		||||
            </span>
 | 
			
		||||
        </button>
 | 
			
		||||
 | 
			
		||||
@@ -23,12 +23,12 @@
 | 
			
		||||
            class="btn"
 | 
			
		||||
            :class="overrideClass"
 | 
			
		||||
            type="button"
 | 
			
		||||
            :title="$t('markAsRead')"
 | 
			
		||||
            :title="trans(NOTIFICATION_MARK_AS_READ)"
 | 
			
		||||
            @click="markAsRead"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-sm fa-envelope-open-o" />
 | 
			
		||||
            <i class="fa fa-sm fa-envelope-open-o"></i>
 | 
			
		||||
            <span v-if="!buttonNoText" class="ps-2">
 | 
			
		||||
                {{ $t("markAsRead") }}
 | 
			
		||||
                {{ trans(NOTIFICATION_MARK_AS_READ) }}
 | 
			
		||||
            </span>
 | 
			
		||||
        </button>
 | 
			
		||||
 | 
			
		||||
@@ -37,9 +37,9 @@
 | 
			
		||||
            type="button"
 | 
			
		||||
            class="btn btn-outline-primary"
 | 
			
		||||
            :href="showUrl"
 | 
			
		||||
            :title="$t('action.show')"
 | 
			
		||||
            :title="trans(SEE)"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-sm fa-comment-o" />
 | 
			
		||||
            <i class="fa fa-sm fa-comment-o"></i>
 | 
			
		||||
        </a>
 | 
			
		||||
 | 
			
		||||
        <!-- "Mark All Read" button -->
 | 
			
		||||
@@ -51,7 +51,7 @@
 | 
			
		||||
            :title="$t('markAllRead')"
 | 
			
		||||
            @click="markAllRead"
 | 
			
		||||
        >
 | 
			
		||||
            <i class="fa fa-sm fa-envelope-o" />
 | 
			
		||||
            <i class="fa fa-sm fa-envelope-o"></i>
 | 
			
		||||
            <span v-if="!buttonNoText" class="ps-2">
 | 
			
		||||
                {{ $t("markAllRead") }}
 | 
			
		||||
            </span>
 | 
			
		||||
@@ -59,89 +59,66 @@
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
<script setup>
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
 | 
			
		||||
import {
 | 
			
		||||
    trans,
 | 
			
		||||
    NOTIFICATION_MARK_AS_READ,
 | 
			
		||||
    NOTIFICATION_MARK_AS_UNREAD,
 | 
			
		||||
    SEE,
 | 
			
		||||
} from "translator";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "NotificationReadToggle",
 | 
			
		||||
    props: {
 | 
			
		||||
        isRead: {
 | 
			
		||||
            required: true,
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
        },
 | 
			
		||||
        notificationId: {
 | 
			
		||||
            required: true,
 | 
			
		||||
            type: Number,
 | 
			
		||||
        },
 | 
			
		||||
        // Optional
 | 
			
		||||
        buttonClass: {
 | 
			
		||||
            required: false,
 | 
			
		||||
            type: String,
 | 
			
		||||
        },
 | 
			
		||||
        buttonNoText: {
 | 
			
		||||
            required: false,
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
        },
 | 
			
		||||
        showUrl: {
 | 
			
		||||
            required: false,
 | 
			
		||||
            type: String,
 | 
			
		||||
        },
 | 
			
		||||
// Props
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    isRead: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    emits: ["markRead", "markUnread"],
 | 
			
		||||
    computed: {
 | 
			
		||||
        /// [Option] override default button appearance (btn-misc)
 | 
			
		||||
        overrideClass() {
 | 
			
		||||
            return this.buttonClass ? this.buttonClass : "btn-misc";
 | 
			
		||||
        },
 | 
			
		||||
        /// [Option] don't display text on button
 | 
			
		||||
        buttonHideText() {
 | 
			
		||||
            return this.buttonNoText;
 | 
			
		||||
        },
 | 
			
		||||
        /// [Option] showUrl is href for show page second button.
 | 
			
		||||
        //  When passed, the component return a button-group with 2 buttons.
 | 
			
		||||
        isButtonGroup() {
 | 
			
		||||
            return this.showUrl;
 | 
			
		||||
        },
 | 
			
		||||
    notificationId: {
 | 
			
		||||
        type: Number,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        markAsUnread() {
 | 
			
		||||
            makeFetch(
 | 
			
		||||
                "POST",
 | 
			
		||||
                `/api/1.0/main/notification/${this.notificationId}/mark/unread`,
 | 
			
		||||
                [],
 | 
			
		||||
            ).then(() => {
 | 
			
		||||
                this.$emit("markRead", { notificationId: this.notificationId });
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        markAsRead() {
 | 
			
		||||
            makeFetch(
 | 
			
		||||
                "POST",
 | 
			
		||||
                `/api/1.0/main/notification/${this.notificationId}/mark/read`,
 | 
			
		||||
                [],
 | 
			
		||||
            ).then(() => {
 | 
			
		||||
                this.$emit("markUnread", {
 | 
			
		||||
                    notificationId: this.notificationId,
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        markAllRead() {
 | 
			
		||||
            makeFetch(
 | 
			
		||||
                "POST",
 | 
			
		||||
                `/api/1.0/main/notification/markallread`,
 | 
			
		||||
                [],
 | 
			
		||||
            ).then(() => {
 | 
			
		||||
                this.$emit("markAllRead");
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
    buttonClass: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: false,
 | 
			
		||||
    },
 | 
			
		||||
    i18n: {
 | 
			
		||||
        messages: {
 | 
			
		||||
            fr: {
 | 
			
		||||
                markAsUnread: "Marquer comme non-lu",
 | 
			
		||||
                markAsRead: "Marquer comme lu",
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    buttonNoText: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: false,
 | 
			
		||||
    },
 | 
			
		||||
    showUrl: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: false,
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Emits
 | 
			
		||||
const emit = defineEmits(["markRead", "markUnread"]);
 | 
			
		||||
 | 
			
		||||
// Computed
 | 
			
		||||
const overrideClass = computed(() => props.buttonClass || "btn-misc");
 | 
			
		||||
const isButtonGroup = computed(() => props.showUrl);
 | 
			
		||||
 | 
			
		||||
// Methods
 | 
			
		||||
const markAsUnread = () => {
 | 
			
		||||
    makeFetch(
 | 
			
		||||
        "POST",
 | 
			
		||||
        `/api/1.0/main/notification/${props.notificationId}/mark/unread`,
 | 
			
		||||
        [],
 | 
			
		||||
    ).then(() => {
 | 
			
		||||
        emit("markRead", { notificationId: props.notificationId });
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const markAsRead = () => {
 | 
			
		||||
    makeFetch(
 | 
			
		||||
        "POST",
 | 
			
		||||
        `/api/1.0/main/notification/${props.notificationId}/mark/read`,
 | 
			
		||||
        [],
 | 
			
		||||
    ).then(() => {
 | 
			
		||||
        emit("markUnread", { notificationId: props.notificationId });
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,253 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <a
 | 
			
		||||
        v-if="isOpenDocument"
 | 
			
		||||
        class="btn"
 | 
			
		||||
        :class="[
 | 
			
		||||
            isChangeIcon ? 'change-icon' : '',
 | 
			
		||||
            isChangeClass ? options.changeClass : 'btn-wopilink',
 | 
			
		||||
        ]"
 | 
			
		||||
        @click="openModal"
 | 
			
		||||
    >
 | 
			
		||||
        <i v-if="isChangeIcon" class="fa me-2" :class="options.changeIcon" />
 | 
			
		||||
 | 
			
		||||
        <span v-if="!noText">
 | 
			
		||||
            {{ $t("online_edit_document") }}
 | 
			
		||||
        </span>
 | 
			
		||||
    </a>
 | 
			
		||||
 | 
			
		||||
    <teleport to="body">
 | 
			
		||||
        <div class="wopi-frame" v-if="isOpenDocument">
 | 
			
		||||
            <modal
 | 
			
		||||
                v-if="modal.showModal"
 | 
			
		||||
                :modal-dialog-class="modal.modalDialogClass"
 | 
			
		||||
                :hide-footer="true"
 | 
			
		||||
                @close="modal.showModal = false"
 | 
			
		||||
            >
 | 
			
		||||
                <template #header>
 | 
			
		||||
                    <img class="logo" :src="logo" height="45" />
 | 
			
		||||
                    <span class="ms-auto me-3">
 | 
			
		||||
                        <span v-if="options.title">{{ options.title }}</span>
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <!--
 | 
			
		||||
                  <a class="btn btn-outline-light">
 | 
			
		||||
                     <i class="fa fa-save fa-fw"></i>
 | 
			
		||||
                     {{ $t('save_and_quit') }}
 | 
			
		||||
                  </a>
 | 
			
		||||
                  -->
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <template #body>
 | 
			
		||||
                    <div v-if="loading" class="loading">
 | 
			
		||||
                        <i
 | 
			
		||||
                            class="fa fa-circle-o-notch fa-spin fa-3x"
 | 
			
		||||
                            :title="$t('loading')"
 | 
			
		||||
                        />
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <iframe :src="this.wopiUrl" @load="loaded" />
 | 
			
		||||
                </template>
 | 
			
		||||
            </modal>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div v-else>
 | 
			
		||||
            <modal
 | 
			
		||||
                v-if="modal.showModal"
 | 
			
		||||
                modal-dialog-class="modal-sm"
 | 
			
		||||
                @close="modal.showModal = false"
 | 
			
		||||
            >
 | 
			
		||||
                <template #header>
 | 
			
		||||
                    <h3>{{ $t("invalid_title") }}</h3>
 | 
			
		||||
                </template>
 | 
			
		||||
                <template #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,
 | 
			
		||||
        },
 | 
			
		||||
        type: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        options: {
 | 
			
		||||
            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.options.noText !== "undefined") {
 | 
			
		||||
                return this.options.noText === true;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        isChangeIcon() {
 | 
			
		||||
            if (typeof this.options.changeIcon !== "undefined") {
 | 
			
		||||
                return !(
 | 
			
		||||
                    this.options.changeIcon === null ||
 | 
			
		||||
                    this.options.changeIcon === ""
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
        isChangeClass() {
 | 
			
		||||
            if (typeof this.options.changeClass !== "undefined") {
 | 
			
		||||
                return !(
 | 
			
		||||
                    this.options.changeClass === null ||
 | 
			
		||||
                    this.options.changeClass === ""
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        openModal() {
 | 
			
		||||
            this.loading = true;
 | 
			
		||||
            this.modal.showModal = true;
 | 
			
		||||
        },
 | 
			
		||||
        loaded() {
 | 
			
		||||
            this.loading = false;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    i18n: {
 | 
			
		||||
        messages: {
 | 
			
		||||
            fr: {
 | 
			
		||||
                online_edit_document: "Éditer en ligne",
 | 
			
		||||
                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>
 | 
			
		||||
@@ -54,6 +54,11 @@ const messages = {
 | 
			
		||||
            residential_address: "Adresse de résidence",
 | 
			
		||||
            located_at: "réside chez",
 | 
			
		||||
        },
 | 
			
		||||
        comment: {
 | 
			
		||||
            label: "Commentaire",
 | 
			
		||||
            editor_simple: "Simple",
 | 
			
		||||
            editor_rich: "Riche"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -136,6 +136,59 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<h2>Fix the title in the flex table</h2>
 | 
			
		||||
 | 
			
		||||
<p>This will fix the layout of the row, with a "title" element, and an aside element. Using <code>css grid</code>, this is quite safe and won't overflow</p>
 | 
			
		||||
 | 
			
		||||
<xmp>
 | 
			
		||||
    <div class="flex-table">
 | 
			
		||||
        <div class="item-bloc">
 | 
			
		||||
            <div class="item-row">
 | 
			
		||||
                <div class="item-two-col-grid">
 | 
			
		||||
                    <div class="title">This is my title</div>
 | 
			
		||||
                    <div class="aside">Aside value</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="item-bloc">
 | 
			
		||||
            <div class="item-row">
 | 
			
		||||
                <div class="item-two-col-grid">
 | 
			
		||||
                    <div class="title">
 | 
			
		||||
                        <div><h3>This is my title, which can be very long and take a lot of place. But it is wrapped successfully, and won't disturb the placement of the aside block</h3></div>
 | 
			
		||||
                        <div>This is a second line</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="aside">Aside value</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</xmp>
 | 
			
		||||
 | 
			
		||||
    <p>will render:</p>
 | 
			
		||||
 | 
			
		||||
    <div class="flex-table">
 | 
			
		||||
        <div class="item-bloc">
 | 
			
		||||
            <div class="item-row">
 | 
			
		||||
                <div class="item-two-col-grid">
 | 
			
		||||
                    <div class="title">This is my title</div>
 | 
			
		||||
                    <div class="aside">Aside value</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="item-bloc">
 | 
			
		||||
            <div class="item-row">
 | 
			
		||||
                <div class="item-two-col-grid">
 | 
			
		||||
                    <div class="title">
 | 
			
		||||
                        <div><h3>This is my title, which can be very long and take a lot of place. But it is wrapped successfully, and won't disturb the placement of the aside block</h3></div>
 | 
			
		||||
                        <div>This is a second line</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="aside">Aside value</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h2>Wrap-list</h2>
 | 
			
		||||
<p>Une liste inline qui s'aligne, puis glisse sous son titre.</p>
 | 
			
		||||
<div class="wrap-list debug">
 | 
			
		||||
@@ -392,4 +445,12 @@ Toutes les classes btn-* de bootstrap sont fonctionnelles
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <h1>Badges</h1>
 | 
			
		||||
 | 
			
		||||
    <span class="badge-accompanying-work-type-simple">Action d'accompagnement</span>
 | 
			
		||||
    <span class="badge-activity-type-simple">Type d'échange</span>
 | 
			
		||||
    <span class="badge-calendar-simple">Rendez-vous</span>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -214,7 +214,9 @@
 | 
			
		||||
 | 
			
		||||
{% block private_comment_widget %}
 | 
			
		||||
    {% for entry in form %}
 | 
			
		||||
        {{ form_widget(entry) }}
 | 
			
		||||
        <div id="comment-app-{{ form.vars.id }}" data-field-name="{{ form.vars.full_name }}">
 | 
			
		||||
            {{ form_widget(entry, { attr: { ckeditor: 'true' } }) }}
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
@@ -224,7 +226,9 @@
 | 
			
		||||
 | 
			
		||||
{% block comment_widget %}
 | 
			
		||||
    {% for entry in form %}
 | 
			
		||||
        {{ form_widget(entry) }}
 | 
			
		||||
        <div id="comment-app-{{ form.vars.id }}" data-field-name="{{ form.vars.full_name }}">
 | 
			
		||||
            {{ form_widget(entry, { attr: { ckeditor: 'true' } }) }}
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
{% endblock comment_widget %}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
    {{ 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') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_document_action_buttons_group') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_workflow_attachment') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@@ -19,7 +18,6 @@
 | 
			
		||||
    {{ 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') }}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_document_action_buttons_group') }}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_workflow_attachment') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ class GenderDocGenNormalizer implements ContextAwareNormalizerInterface, Normali
 | 
			
		||||
            'id' => $gender->getId(),
 | 
			
		||||
            'label' => $this->translatableStringHelper->localize($gender->getLabel()),
 | 
			
		||||
            'genderTranslation' => $gender->getGenderTranslation(),
 | 
			
		||||
            'type' => 'chill_main_gender',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -68,8 +68,8 @@ class AddressReferenceBEFromBestAddress
 | 
			
		||||
        $csv->setDelimiter(',');
 | 
			
		||||
        $csv->setHeaderOffset(0);
 | 
			
		||||
 | 
			
		||||
        $stmt = Statement::create()
 | 
			
		||||
            ->process($csv);
 | 
			
		||||
        $stmt = new Statement();
 | 
			
		||||
        $stmt = $stmt->process($csv);
 | 
			
		||||
 | 
			
		||||
        foreach ($stmt as $record) {
 | 
			
		||||
            $this->baseImporter->importAddress(
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user