Content
View differences
Updated by Aleix Suau about 5 years ago
For work packages, fields can be configured as multiple selections for all projects or for individual projects. The same function is desired for user-defined fields of the type Project.
**Acceptance requirements**
* The administration of custom fields for projects gets a checkbox "Allow multi-select", just like the lists for work packages
* The project form is extended such that list custom fields can be multi-selected
* The project advanced settings is extended such that list custom fields can be multi-selected
* The project overview list/table is extended to show multi-select custom fields
* The project details widget on the project overview / dashboard displays custom lists with multiple selections.
* When copying projects, multi-selection custom fields are also copied
<figure class="image op-uc-figure"><div class="op-uc-figure--content"><img class="op-uc-image" src="/api/v3/attachments/20761/content"></div></figure>
### Development Notes
* Test route: http://localhost:4200/projects/demo-project/settings/generic/
* Admin > Custom fields > Wps > multiselect checkbox
* Project > Overview > Project details should allow multi-select custom fields
* Form Config:
* [https://docs.openproject.org/api/endpoints/projects/](https://docs.openproject.org/api/endpoints/projects/)
* [https://docs.openproject.org/api/endpoints/projects/#projects-projects-schema](https://docs.openproject.org/api/endpoints/projects/#projects-projects-schema)
* [https://docs.openproject.org/api/endpoints/projects/#projects-project-create-form](https://docs.openproject.org/api/endpoints/projects/#projects-project-create-form)
* 3 steps:
* Replace view with formly
* Enable the backend capable of multiselect fields project
* Enable multiselect fields project in the frontend
### Dev requirements
* Change Sources:
* Layout:
* Schema loading (FormConfig):
When the user changes the type.
* First load
* Schema change
* Model:
* Schema loading (Payload (Model + Default values)) :
When the user changes the type.
* First load
* Schema change
* User interaction
* Form component:
* 2 ways of getting its config:
* New >>> POST to _api/v3/projects/\[projectId\]/work\_packages/form_ with payload _{\_links: {type: {href: "/api/v3/types/1"}}}_
* Existing >>> POST _api/v3/work\_packages/\[wp\_id\]/form_ with payload _{lockVersion: 2, \_links: {}}_
###
### DynamicForm use cases:
* Standalone Form:
* settings
* from backend
* from @Input
* submit
* needs resourcePath
* FormControl
* settings
* from backend
* from @Input
* submit
* NO
### TODO
* [ ] A <formly-field> tag is wrapping all the <formly-field> tags (could be related with the way the groups are defined (\_links...))
* [ ] Handle general server errors (right now it is always showing 'Please...')
* [ ] fix/fix-form-styles / form-field wrapping the entire form
* [ ] debug why moving FormGroup out of the \_setupDynamicForm breaks the expressionProperties
* [ ] Submit form.getRawValue to avoid missing disabled fields
* [ ] op-form-group--label styles?
* [ ] Review API responses Typings
* [ ] A <formly-field> tag is wrapping all the <formly-field> tags (could be related with the way the groups are defined (\_links...))
* [x] Open advanced settings when there is an invalid field
* [x] (Other ticket) The select fields should have autocompleters IMO. After all, this would highlight the benefit of having turned it into an Angular form.
* [x] CSS Animation?
* [x] Extract the create group function to dynamic forms
* [x] Attribute help texts
* [x] Handle `_meta.*` properties similar to `_links`
* [ ] Remaining Tests
* [ ] Documentation
* [x] CSS:
* [x] new project form doesn't expand all the width
* [x] field with error hides red border on hover
* [x] form.payload.name default value is "" (?)
* [x] Merge: The Active field should not be rendered as the functionality is handled via the Archive/Unarchive button
* [x] Allow to update only the payload (currently all the formSettings are updated at the same time wich would lead to reload the entire form in order to just set the model).
* [x] The Status field, now that we are in angular, should have that bulb similar to how it is in the widget
* [x] Sort fields in the front
* [x] Replace project setting's Information tab:
* [x] exclude required disk storage
* [x] Review TODOs
* [x] Hide non-writable fields
* [x] Hide identifier
* [x] Multiselect custom fields
* [x] Top left buttons (subproject, copy project...)
* [x] Next steps:
* [x] Clean useless code and do a draft PR (wp specific case)
* [x] Op-form-field
* [x] Differentiate between update/create form (/id or href)
* [x] Create routes:
* [x] Take the formId from the params?
* [x] Custom fields (starting with \[\])
* [x] Print form
* [x] Fill model
* [x] Default values
* [x] Group fields
* [x] Layout
* [x] Validation
* [x] Sync
* [x] Async
* [x] Custom component
* [x] Send to endpoint
* [x] Postprocess the model
* [x] Set default values if the user has deleted the default value
* [ ] New Inputs:
* [x] TextEditFieldComponent
* [x] IntegerEditFieldComponent
* [x] SelectEditFieldComponent
* [x] MultiSelectEditFieldComponent
* [x] DateEditFieldComponent
* [x] two datepickers are displayed
* [x] not close on blur
* [x] displayed when invalid (also the rest of the project)
* [x] not disabled properly when formControl.disable
* [x] FormattableEditFieldComponent
* [x] _onTouch not working this_.editor.ckEditorInstance.ui.focusTracker.on( 'change:isFocused'
* [x] FloatEditFieldComponent
* [x] BooleanEditFieldComponent
* [ ] Others
* [x] Translations
* [x] Manage focus
* [x] ng-select
* [x] Between fields with tabs (inline edit)
* [x] Routes
* [x] Existing form route
* [x] New form route
* [x] Redirect when new form is created
* [x] Resolve data before entering the route?
* [x] Check touched, disabled, change, onsubmit... on every new input (datepicker)
* [x] User feedback on submit success/error
* [x] Import only necessary fields from OpenprojectFieldsModule into DynamicFormsModule (EditFieldControlsComponent)
* [x] Where do we place the submit button?
## **Dynamic V2**
* [ ] Accesibility
* [ ] Decouple inputs from the dynamic forms so they can be used outside of a dynamic form
* [ ] DynamicFormModule: import only needed dependencies (currently it is importing the entire CommonModule)
* [ ] Create fieldGroups @Input to allow create fieldGroups by passing down the group name, key and field to aggreagate.
* [ ] Validation: Handle multiple errors per field
* [ ] Optimization: Remove '\_links' from the model in the front, just add them in the formatToSubmit process.
* [ ] Changing the @Input model rerenders the entire form. Can't use DynamicFormComponent.form.setValue() (that doesn't rerenders) right now because the backend payload format is not the same as the form (.\_links).
* [ ] Improve performance:
* [ ] CkEditor
* [ ] Dynamic form reloaded when new resource is created (because we redirect to the new url, the resourceId changes...)
* [ ] Content projection:
* [ ] Allow the developer to project the content (layout, op-form-field, formly-fields...) so it is more flexible
* [ ] Save
* [ ] Save the entire form when it is new
* [ ] Save on every field edit when it has model
* [ ] Remove values that don't belong to the schema (e.g. if the user has filled some custom fields and then changed the type )
* [ ] Manage:
* [ ] LockVersion
* [ ] Id (on new wps)
* [ ] Replace selects with the the op-autocompleter?
* [ ] Handle remaining field types (from _initializeCoreEditFields_):
* [ ] ProjectStatusEditFieldComponent
* [ ] WorkPackageCommentFieldComponent
* [ ] CombinedDateEditFieldComponent
* [ ] PlainFormattableEditFieldComponent
* [ ] TimeEntryWorkPackageEditFieldComponent
* [ ] DurationEditFieldComponent
* [ ] WorkPackageEditFieldComponent
* [ ] SelectEditFieldComponent:
* [ ] 3 flavours:
* [ ] CreateAutocompleterComponent
* [ ] VersionAutocompleterComponent (+ @Output create + createNewVersion + ngselect.addTag)
* [ ] WorkPackageAutocompleterComponent
* [ ] Why/how do we sort option this.halSorting.sort(availableValues)?
* [ ] What is addEmptyOption()?
* [ ] Open directly this.\_autocompleterComponent.openDirectly = true;?
* [ ] Optimization:
* [ ] Manage results with pagination
* [ ] Skip extra calls when all results are returned (no pagination)
* [ ] FormattableEditFieldComponent
* [ ] editorType
* [ ] HalResource >> constrained
* [ ] ProjectResource >> 'statusExplanation' || 'description' >> full, other constrained)
* [ ] _WorkPackageBaseResource: fieldName_ === 'description' ? 'full' : 'constrained';
* [ ] CustomTextEditFieldService >> full
* [ ] What is previewContext for?
* [ ] Implement _edit-field-controls_
* [ ] Combo inputs (country > province)
* [ ] Click and edit
* [ ] _\[disabled\]_\="inFlight"?
* [ ] EditFieldHandler.handleUserKeydown:
"Handle users pressing enter inside an edit mode. Outside an edit mode, the regular save event is captured by handleUserSubmit (submit event). In an edit mode, we can't derive from a submit event wheteher the user pressed enter (and on what field he did that).
* [ ] Seems that it is only implemented in the ckEditor
* [ ] Unify options (select/multiselect) format: Different data format for options: sometimes they are resources, sometimes they don't, sometimes they have \_links.self.title other don't.
* [ ] Tests:
* [ ] field wrappers
* [ ] Form inputs outside of the form (how do we deal with it?)
* [ ] Wp type
* [ ] Hide op-form-field wrapper when the formly-field is hidden dynamically
* [ ] I like the idea that the pathhelperService is the responsible of building the form path.I’d also like to provide a simple API so you can load a form without knowing anything about HAL resources or PathHelper. Both ideas are not incompatible, the component could have: @Input formHref, Input resource: ‘project’ | ‘user’ | …, Input resourceId, So it can be used easy in all the scenarios (loading from resource, loading form params, loading from template…)
* [ ] Handle dynamic resourceId @Input (currently if the resourceId is async (@resourceId="resourceId$ | async")) the call to the backend is done twice and we rely on race conditions (the call without id could return earlier and ew end up with a void form).
* [ ] Customizations:
* [ ] Hide/Exclude some fields
* [ ] Add some fields
* [ ] Keep state between form reloads (when clicking on expand form in splitting views). There is a closed PRs with this changes
* [ ] Valid result (In this order) = Form config + Form Payload + User Changes (that applies to the active Type)
* [ ] Whenever the Type is changes, we have to reapply the entire previous sequence.
* [ ] Whenever the form is submitted, the User Changes have to be reset
* [ ] _DynamicFormsHub Use cases:_
* [ ] _Keeps a reference of every active form_
* [ ] _Registers a form when it is created_
* [ ] _Removes a form when it is destroyed_
* [ ] _Keeps the unsaved changes_
* [ ] On route changes, o\_nly when they are not discarded (maximize side panel).\_
* [ ] _How do we know that the change has not been discarded (alert)_
**Acceptance requirements**
* The administration of custom fields for projects gets a checkbox "Allow multi-select", just like the lists for work packages
* The project form is extended such that list custom fields can be multi-selected
* The project advanced settings is extended such that list custom fields can be multi-selected
* The project overview list/table is extended to show multi-select custom fields
* The project details widget on the project overview / dashboard displays custom lists with multiple selections.
* When copying projects, multi-selection custom fields are also copied
<figure class="image op-uc-figure"><div class="op-uc-figure--content"><img class="op-uc-image" src="/api/v3/attachments/20761/content"></div></figure>
### Development Notes
* Test route: http://localhost:4200/projects/demo-project/settings/generic/
* Admin > Custom fields > Wps > multiselect checkbox
* Project > Overview > Project details should allow multi-select custom fields
* Form Config:
* [https://docs.openproject.org/api/endpoints/projects/](https://docs.openproject.org/api/endpoints/projects/)
* [https://docs.openproject.org/api/endpoints/projects/#projects-projects-schema](https://docs.openproject.org/api/endpoints/projects/#projects-projects-schema)
* [https://docs.openproject.org/api/endpoints/projects/#projects-project-create-form](https://docs.openproject.org/api/endpoints/projects/#projects-project-create-form)
* 3 steps:
* Replace view with formly
* Enable the backend capable of multiselect fields project
* Enable multiselect fields project in the frontend
### Dev requirements
* Change Sources:
* Layout:
* Schema loading (FormConfig):
When the user changes the type.
* First load
* Schema change
* Model:
* Schema loading (Payload (Model + Default values)) :
When the user changes the type.
* First load
* Schema change
* User interaction
* Form component:
* 2 ways of getting its config:
* New >>> POST to _api/v3/projects/\[projectId\]/work\_packages/form_ with payload _{\_links: {type: {href: "/api/v3/types/1"}}}_
* Existing >>> POST _api/v3/work\_packages/\[wp\_id\]/form_ with payload _{lockVersion: 2, \_links: {}}_
###
### DynamicForm use cases:
* Standalone Form:
* settings
* from backend
* from @Input
* submit
* needs resourcePath
* FormControl
* settings
* from backend
* from @Input
* submit
* NO
### TODO
* [ ] A <formly-field> tag is wrapping all the <formly-field> tags (could be related with the way the groups are defined (\_links...))
* [ ] Handle general server errors (right now it is always showing 'Please...')
* [ ] fix/fix-form-styles / form-field wrapping the entire form
* [ ] debug why moving FormGroup out of the \_setupDynamicForm breaks the expressionProperties
* [ ] Submit form.getRawValue to avoid missing disabled fields
* [ ] op-form-group--label styles?
* [ ] Review API responses Typings
* [ ] A <formly-field> tag is wrapping all the <formly-field> tags (could be related with the way the groups are defined (\_links...))
* [x] Open advanced settings when there is an invalid field
* [x] (Other ticket) The select fields should have autocompleters IMO. After all, this would highlight the benefit of having turned it into an Angular form.
* [x] CSS Animation?
* [x] Extract the create group function to dynamic forms
* [x] Attribute help texts
* [x] Handle `_meta.*` properties similar to `_links`
* [ ] Remaining Tests
* [ ] Documentation
* [x] CSS:
* [x] new project form doesn't expand all the width
* [x] field with error hides red border on hover
* [x] form.payload.name default value is "" (?)
* [x] Merge: The Active field should not be rendered as the functionality is handled via the Archive/Unarchive button
* [x] Allow to update only the payload (currently all the formSettings are updated at the same time wich would lead to reload the entire form in order to just set the model).
* [x] The Status field, now that we are in angular, should have that bulb similar to how it is in the widget
* [x] Sort fields in the front
* [x] Replace project setting's Information tab:
* [x] exclude required disk storage
* [x] Review TODOs
* [x] Hide non-writable fields
* [x] Hide identifier
* [x] Multiselect custom fields
* [x] Top left buttons (subproject, copy project...)
* [x] Next steps:
* [x] Clean useless code and do a draft PR (wp specific case)
* [x] Op-form-field
* [x] Differentiate between update/create form (/id or href)
* [x] Create routes:
* [x] Take the formId from the params?
* [x] Custom fields (starting with \[\])
* [x] Print form
* [x] Fill model
* [x] Default values
* [x] Group fields
* [x] Layout
* [x] Validation
* [x] Sync
* [x] Async
* [x] Custom component
* [x] Send to endpoint
* [x] Postprocess the model
* [x] Set default values if the user has deleted the default value
* [ ] New Inputs:
* [x] TextEditFieldComponent
* [x] IntegerEditFieldComponent
* [x] SelectEditFieldComponent
* [x] MultiSelectEditFieldComponent
* [x] DateEditFieldComponent
* [x] two datepickers are displayed
* [x] not close on blur
* [x] displayed when invalid (also the rest of the project)
* [x] not disabled properly when formControl.disable
* [x] FormattableEditFieldComponent
* [x] _onTouch not working this_.editor.ckEditorInstance.ui.focusTracker.on( 'change:isFocused'
* [x] FloatEditFieldComponent
* [x] BooleanEditFieldComponent
* [ ] Others
* [x] Translations
* [x] Manage focus
* [x] ng-select
* [x] Between fields with tabs (inline edit)
* [x] Routes
* [x] Existing form route
* [x] New form route
* [x] Redirect when new form is created
* [x] Resolve data before entering the route?
* [x] Check touched, disabled, change, onsubmit... on every new input (datepicker)
* [x] User feedback on submit success/error
* [x] Import only necessary fields from OpenprojectFieldsModule into DynamicFormsModule (EditFieldControlsComponent)
* [x] Where do we place the submit button?
## **Dynamic V2**
* [ ] Accesibility
* [ ] Decouple inputs from the dynamic forms so they can be used outside of a dynamic form
* [ ] DynamicFormModule: import only needed dependencies (currently it is importing the entire CommonModule)
* [ ] Create fieldGroups @Input to allow create fieldGroups by passing down the group name, key and field to aggreagate.
* [ ] Validation: Handle multiple errors per field
* [ ] Optimization: Remove '\_links' from the model in the front, just add them in the formatToSubmit process.
* [ ] Changing the @Input model rerenders the entire form. Can't use DynamicFormComponent.form.setValue() (that doesn't rerenders) right now because the backend payload format is not the same as the form (.\_links).
* [ ] Improve performance:
* [ ] CkEditor
* [ ] Dynamic form reloaded when new resource is created (because we redirect to the new url, the resourceId changes...)
* [ ] Content projection:
* [ ] Allow the developer to project the content (layout, op-form-field, formly-fields...) so it is more flexible
* [ ] Save
* [ ] Save the entire form when it is new
* [ ] Save on every field edit when it has model
* [ ] Remove values that don't belong to the schema (e.g. if the user has filled some custom fields and then changed the type )
* [ ] Manage:
* [ ] LockVersion
* [ ] Id (on new wps)
* [ ] Replace selects with the the op-autocompleter?
* [ ] Handle remaining field types (from _initializeCoreEditFields_):
* [ ] ProjectStatusEditFieldComponent
* [ ] WorkPackageCommentFieldComponent
* [ ] CombinedDateEditFieldComponent
* [ ] PlainFormattableEditFieldComponent
* [ ] TimeEntryWorkPackageEditFieldComponent
* [ ] DurationEditFieldComponent
* [ ] WorkPackageEditFieldComponent
* [ ] SelectEditFieldComponent:
* [ ] 3 flavours:
* [ ] CreateAutocompleterComponent
* [ ] VersionAutocompleterComponent (+ @Output create + createNewVersion + ngselect.addTag)
* [ ] WorkPackageAutocompleterComponent
* [ ] Why/how do we sort option this.halSorting.sort(availableValues)?
* [ ] What is addEmptyOption()?
* [ ] Open directly this.\_autocompleterComponent.openDirectly = true;?
* [ ] Optimization:
* [ ] Manage results with pagination
* [ ] Skip extra calls when all results are returned (no pagination)
* [ ] FormattableEditFieldComponent
* [ ] editorType
* [ ] HalResource >> constrained
* [ ] ProjectResource >> 'statusExplanation' || 'description' >> full, other constrained)
* [ ] _WorkPackageBaseResource: fieldName_ === 'description' ? 'full' : 'constrained';
* [ ] CustomTextEditFieldService >> full
* [ ] What is previewContext for?
* [ ] Implement _edit-field-controls_
* [ ] Combo inputs (country > province)
* [ ] Click and edit
* [ ] _\[disabled\]_\="inFlight"?
* [ ] EditFieldHandler.handleUserKeydown:
"Handle users pressing enter inside an edit mode. Outside an edit mode, the regular save event is captured by handleUserSubmit (submit event). In an edit mode, we can't derive from a submit event wheteher the user pressed enter (and on what field he did that).
* [ ] Seems that it is only implemented in the ckEditor
* [ ] Unify options (select/multiselect) format: Different data format for options: sometimes they are resources, sometimes they don't, sometimes they have \_links.self.title other don't.
* [ ] Tests:
* [ ] field wrappers
* [ ] Form inputs outside of the form (how do we deal with it?)
* [ ] Wp type
* [ ] Hide op-form-field wrapper when the formly-field is hidden dynamically
* [ ] I like the idea that the pathhelperService is the responsible of building the form path.I’d also like to provide a simple API so you can load a form without knowing anything about HAL resources or PathHelper. Both ideas are not incompatible, the component could have: @Input formHref, Input resource: ‘project’ | ‘user’ | …, Input resourceId, So it can be used easy in all the scenarios (loading from resource, loading form params, loading from template…)
* [ ] Handle dynamic resourceId @Input (currently if the resourceId is async (@resourceId="resourceId$ | async")) the call to the backend is done twice and we rely on race conditions (the call without id could return earlier and ew end up with a void form).
* [ ] Customizations:
* [ ] Hide/Exclude some fields
* [ ] Add some fields
* [ ] Keep state between form reloads (when clicking on expand form in splitting views). There is a closed PRs with this changes
* [ ] Valid result (In this order) = Form config + Form Payload + User Changes (that applies to the active Type)
* [ ] Whenever the Type is changes, we have to reapply the entire previous sequence.
* [ ] Whenever the form is submitted, the User Changes have to be reset
* [ ] _DynamicFormsHub Use cases:_
* [ ] _Keeps a reference of every active form_
* [ ] _Registers a form when it is created_
* [ ] _Removes a form when it is destroyed_
* [ ] _Keeps the unsaved changes_
* [ ] On route changes, o\_nly when they are not discarded (maximize side panel).\_
* [ ] _How do we know that the change has not been discarded (alert)_