[31023] Preparation for project edit fields: Generalize edit and display fields currently work package specific (#7726)

* Check edit fields for Work package dependencies

* Make EditForm, NotificationService, EditContext indepenedent of Work Packages

* Make EventsService independent of WorkPackages

* Start renaming WpNotificationService (WiP)

* Fix more references

* Fix typescript errors

* Add basic halEditingService

* Rename to global halResourceEditingService (WiP)

* Move typing from class to methods (WiP)

* Fix typescript errors

* Remove space in type

* Add test project widget && generalize the editFieldGroup

* Rename editing portal service

[ci skip]

* Rename WpEditFieldComponent

* Rename WpDisplayFields

* Rename display-XX-field to XX-display-field

[ci skip]

* Add WP specific ID field to distinguish between resources

* Re-add state in work package resource

* Generalize display field renderer

* Rename spent-time to wp-spent-time and fix highlight specifics

[ci skip]

* Actually load the project schema and make field editable

* Make edit-field-group.component an edit-form.component and subclass EditForm

* Remove edit context in favor of specialized EditForm

* Add special cases for work package editing

* Fix edit actions bar

* Fix codeclimate issues

* Use WorkPackageNotificationService if necessary

* Override NotificationService for WPs to allow WP specififc notifications (WiP)

* Correctly provide wpNotification service

Because the ui-router doesn't seem to correctly use the parent element's
injector, we need to provide the wpNotification service not in the
wp-base, but rather the wp-list component as well as in the isolated
query space.

* Allow to filter halEvents for specific resourceTypes (e.g. WorkPackage)

* Remove superfluous cell class constant

* Start renaming selectors for wp-edit-field into generics

* Remove wp-table--cell-span in favor of display field selector

* Consolidate other display and edit field styles

* Provide specialized service for transitions in active edit forms

* Remove superfluous overflowSelector

* Accept that date field contains some work package specifics

* Ignore unreadable files

* Provide the changeset for work packages as a hook

Since hal resource editing service is provided per query space, we
cannot register them once (would only work globally)

* Fix dangerfile

* Remove another todo in halResourceNotification service

* Fix npm TestBed for changed dependencies

* Show inplace edit field in project details widget

* Fix highlighting in single view

* Provide HalResourceEditingService outside of project context

* Used typedState for single-view

* Also provide wpNotification service in split view

* Correct check for resource type in eventsService

* Fix getSchemaName in display field renderer

* Fix passing ids into `halEditing.stopEditing`

* Do not globally inject the halResourceEditingService

There's a bug(?) in ui-router that gives you the global service before
the parent injected service for a ui-view

* Fix wpCreate service on copying and parallel creation

* Remove test project widget

* Revert changes for project details widget
pull/7744/head
Henriette Dinger 5 years ago committed by GitHub
parent cd42e7e76a
commit f47a75d153
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 644
      .editorconfig
  2. 4
      Dangerfile
  3. 2
      app/assets/javascripts/onboarding/work_package_tour.js
  4. 26
      app/assets/stylesheets/content/_attributes_group.lsg
  5. 24
      app/assets/stylesheets/content/_in_place_editing.lsg
  6. 1
      app/assets/stylesheets/content/_work_packages.sass
  7. 20
      app/assets/stylesheets/content/work_packages/_table_content.lsg
  8. 17
      app/assets/stylesheets/content/work_packages/_table_content.sass
  9. 2
      app/assets/stylesheets/content/work_packages/_table_inline_create.sass
  10. 33
      app/assets/stylesheets/content/work_packages/inplace_editing/_display_fields.sass
  11. 24
      app/assets/stylesheets/content/work_packages/inplace_editing/_edit_fields.sass
  12. 160
      app/assets/stylesheets/content/work_packages/inplace_editing/_legacy_inplace_styles.sass
  13. 2
      app/assets/stylesheets/content/work_packages/new/_split_view.sass
  14. 6
      app/assets/stylesheets/content/work_packages/new/_type_status_row.sass
  15. 85
      app/assets/stylesheets/content/work_packages/single_view/_inplace_esque_fields.sass
  16. 4
      app/assets/stylesheets/content/work_packages/single_view/_single_view.sass
  17. 4
      app/assets/stylesheets/content/work_packages/tabs/_relations.sass
  18. 4
      app/assets/stylesheets/layout/work_packages/_details_view.sass
  19. 25
      app/assets/stylesheets/layout/work_packages/_full_view.sass
  20. 11
      app/assets/stylesheets/layout/work_packages/_mobile.sass
  21. 2
      app/assets/stylesheets/layout/work_packages/_print.sass
  22. 3
      app/assets/stylesheets/layout/work_packages/_table.sass
  23. 2
      app/assets/stylesheets/layout/work_packages/_table_embedded.sass
  24. 16
      config/locales/js-en.yml
  25. 4
      frontend/doc/PLUGINS.md
  26. 4
      frontend/src/app/angular4-modules.ts
  27. 2
      frontend/src/app/components/main-menu/main-menu-toggle.service.ts
  28. 6
      frontend/src/app/components/modals/save-modal/save-query.modal.ts
  29. 4
      frontend/src/app/components/modals/share-modal/query-sharing.modal.ts
  30. 6
      frontend/src/app/components/modals/wp-destroy-modal/wp-destroy.modal.ts
  31. 7
      frontend/src/app/components/op-context-menu/handlers/wp-create-settings-menu.directive.ts
  32. 24
      frontend/src/app/components/op-context-menu/handlers/wp-status-dropdown-menu.directive.ts
  33. 15
      frontend/src/app/components/projects/project-cache.service.ts
  34. 31
      frontend/src/app/components/schemas/schema-cache.service.ts
  35. 7
      frontend/src/app/components/states/state-cache.service.ts
  36. 12
      frontend/src/app/components/work-packages/work-package-cache.service.spec.ts
  37. 8
      frontend/src/app/components/work-packages/work-package-comment/work-package-comment.component.html
  38. 11
      frontend/src/app/components/work-packages/work-package-comment/work-package-comment.component.ts
  39. 9
      frontend/src/app/components/work-packages/work-package.service.ts
  40. 7
      frontend/src/app/components/work-packages/wp-breadcrumb/wp-breadcrumb-parent.component.ts
  41. 13
      frontend/src/app/components/work-packages/wp-single-view/wp-single-view.component.ts
  42. 14
      frontend/src/app/components/work-packages/wp-single-view/wp-single-view.html
  43. 8
      frontend/src/app/components/work-packages/wp-subject/wp-subject.html
  44. 9
      frontend/src/app/components/work-packages/wp-type-status/wp-type-status.html
  45. 7
      frontend/src/app/components/wp-activity/comment-service.ts
  46. 4
      frontend/src/app/components/wp-activity/user/user-activity.component.ts
  47. 13
      frontend/src/app/components/wp-buttons/wp-status-button/wp-status-button.component.ts
  48. 7
      frontend/src/app/components/wp-card-view/services/wp-card-drag-and-drop.service.ts
  49. 3
      frontend/src/app/components/wp-card-view/styles/wp-card-view.component.sass
  50. 12
      frontend/src/app/components/wp-card-view/wp-card-view.component.html
  51. 5
      frontend/src/app/components/wp-card-view/wp-card-view.component.ts
  52. 13
      frontend/src/app/components/wp-copy/wp-copy.controller.ts
  53. 22
      frontend/src/app/components/wp-custom-actions/wp-custom-actions/wp-custom-action.component.ts
  54. 5
      frontend/src/app/components/wp-details/wp-details-toolbar.component.ts
  55. 90
      frontend/src/app/components/wp-edit-form/display-field-renderer.ts
  56. 106
      frontend/src/app/components/wp-edit-form/single-view-edit-context.ts
  57. 115
      frontend/src/app/components/wp-edit-form/table-edit-form.ts
  58. 59
      frontend/src/app/components/wp-edit-form/work-package-edit-context.ts
  59. 15
      frontend/src/app/components/wp-edit-form/work-package-filter-values.spec.ts
  60. 218
      frontend/src/app/components/wp-edit/wp-edit-field/wp-edit-field-group.directive.ts
  61. 6
      frontend/src/app/components/wp-edit/wp-edit-field/wp-replacement-label.component.ts
  62. 3
      frontend/src/app/components/wp-fast-table/builders/cell-builder.ts
  63. 4
      frontend/src/app/components/wp-fast-table/builders/drag-and-drop/drag-drop-handle-builder.ts
  64. 5
      frontend/src/app/components/wp-fast-table/builders/primary-render-pass.ts
  65. 4
      frontend/src/app/components/wp-fast-table/builders/relations/relation-row-builder.ts
  66. 8
      frontend/src/app/components/wp-fast-table/builders/rows/single-row-builder.ts
  67. 4
      frontend/src/app/components/wp-fast-table/builders/table-action-renderer.ts
  68. 11
      frontend/src/app/components/wp-fast-table/handlers/cell/edit-cell-handler.ts
  69. 4
      frontend/src/app/components/wp-fast-table/handlers/row/double-click-handler.ts
  70. 6
      frontend/src/app/components/wp-fast-table/handlers/state/drag-and-drop-transformer.ts
  71. 28
      frontend/src/app/components/wp-fast-table/wp-table-editing.ts
  72. 6
      frontend/src/app/components/wp-form-group/wp-attribute-group.component.ts
  73. 27
      frontend/src/app/components/wp-form-group/wp-attribute-group.template.html
  74. 8
      frontend/src/app/components/wp-inline-create/inline-create-row-builder.ts
  75. 6
      frontend/src/app/components/wp-inline-create/wp-inline-create.component.ts
  76. 81
      frontend/src/app/components/wp-new/wp-create.controller.ts
  77. 63
      frontend/src/app/components/wp-new/wp-create.service.ts
  78. 16
      frontend/src/app/components/wp-new/wp-new-full-view.html
  79. 15
      frontend/src/app/components/wp-new/wp-new-split-view.html
  80. 9
      frontend/src/app/components/wp-relations/embedded/children/wp-children-query.component.ts
  81. 16
      frontend/src/app/components/wp-relations/embedded/inline/add-existing/wp-relation-inline-add-existing.component.ts
  82. 17
      frontend/src/app/components/wp-relations/embedded/relations/wp-relation-query.component.ts
  83. 24
      frontend/src/app/components/wp-relations/wp-relation-row/wp-relation-row.component.ts
  84. 10
      frontend/src/app/components/wp-relations/wp-relation-row/wp-relation-row.template.html
  85. 7
      frontend/src/app/components/wp-relations/wp-relations-create/wp-relations-autocomplete/wp-relations-autocomplete.component.ts
  86. 19
      frontend/src/app/components/wp-relations/wp-relations-create/wp-relations-create.component.ts
  87. 24
      frontend/src/app/components/wp-relations/wp-relations-hierarchy/wp-relations-hierarchy.service.ts
  88. 11
      frontend/src/app/components/wp-single-view-tabs/watchers-tab/watchers-tab.component.ts
  89. 21
      frontend/src/app/components/wp-table/configuration-modal/wp-table-configuration.modal.ts
  90. 15
      frontend/src/app/components/wp-table/drag-and-drop/actions/group-by-drag-action.service.ts
  91. 25
      frontend/src/app/components/wp-table/timeline/cells/wp-timeline-cell-mouse-handler.ts
  92. 20
      frontend/src/app/components/wp-table/timeline/cells/wp-timeline-cell.ts
  93. 8
      frontend/src/app/components/wp-table/timeline/cells/wp-timeline-cells-renderer.ts
  94. 23
      frontend/src/app/components/wp-table/timeline/container/wp-timeline-container.directive.ts
  95. 1
      frontend/src/app/components/wp-table/wp-table.directive.ts
  96. 4
      frontend/src/app/helpers/rxjs/debounced-input-switchmap.ts
  97. 4
      frontend/src/app/modules/attachments/attachment-list/attachment-list-item.component.ts
  98. 2
      frontend/src/app/modules/attachments/attachment-list/attachment-list-item.html
  99. 6
      frontend/src/app/modules/boards/board/board-actions/version/version-action.service.ts
  100. 20
      frontend/src/app/modules/boards/board/board-list/board-list.component.ts
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,10 +1,642 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,rb,ts}]
charset = utf-8
end_of_line = lf
indent_size = 2
ij_continuation_indent_size = 2
indent_style = space
insert_final_newline = false
max_line_length = 120
tab_width = 2
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_wrap_on_typing = false
[*.css]
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = 0
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
ij_css_hex_color_upper_case = false
ij_css_keep_blank_lines_in_code = 2
ij_css_keep_indents_on_empty_lines = false
ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_value_alignment = 0
[*.feature]
indent_size = 2
ij_gherkin_keep_indents_on_empty_lines = false
[*.haml]
indent_size = 2
ij_haml_keep_indents_on_empty_lines = false
[*.less]
indent_size = 2
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_brace_placement = 0
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_value_alignment = 0
[*.pp]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_puppet_keep_indents_on_empty_lines = false
[*.sass]
indent_size = 2
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_value_alignment = 0
[*.scss]
indent_size = 2
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_brace_placement = 0
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
ij_scss_hex_color_upper_case = false
ij_scss_keep_blank_lines_in_code = 2
ij_scss_keep_indents_on_empty_lines = false
ij_scss_keep_single_line_blocks = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_value_alignment = 0
[*.slim]
indent_size = 2
ij_slim_keep_indents_on_empty_lines = false
[*.styl]
indent_size = 2
ij_stylus_align_closing_brace_with_properties = false
ij_stylus_blank_lines_around_nested_selector = 1
ij_stylus_blank_lines_between_blocks = 1
ij_stylus_brace_placement = 0
ij_stylus_hex_color_long_format = false
ij_stylus_hex_color_lower_case = false
ij_stylus_hex_color_short_format = false
ij_stylus_hex_color_upper_case = false
ij_stylus_keep_blank_lines_in_code = 2
ij_stylus_keep_indents_on_empty_lines = false
ij_stylus_keep_single_line_blocks = false
ij_stylus_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_stylus_space_after_colon = true
ij_stylus_space_before_opening_brace = true
ij_stylus_value_alignment = 0
[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.cjsx,*.coffee}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_coffeescript_align_function_body = false
ij_coffeescript_align_imports = false
ij_coffeescript_align_multiline_array_initializer_expression = true
ij_coffeescript_align_multiline_parameters = true
ij_coffeescript_align_multiline_parameters_in_calls = false
ij_coffeescript_align_object_properties = 0
ij_coffeescript_align_union_types = false
ij_coffeescript_align_var_statements = 0
ij_coffeescript_array_initializer_new_line_after_left_brace = false
ij_coffeescript_array_initializer_right_brace_on_new_line = false
ij_coffeescript_array_initializer_wrap = normal
ij_coffeescript_blacklist_imports = rxjs/Rx,node_modules/**/*,@angular/material,@angular/material/typings/**
ij_coffeescript_blank_lines_around_function = 1
ij_coffeescript_call_parameters_new_line_after_left_paren = false
ij_coffeescript_call_parameters_right_paren_on_new_line = false
ij_coffeescript_call_parameters_wrap = normal
ij_coffeescript_chained_call_dot_on_new_line = true
ij_coffeescript_comma_on_new_line = false
ij_coffeescript_enforce_trailing_comma = keep
ij_coffeescript_field_prefix = _
ij_coffeescript_file_name_style = relaxed
ij_coffeescript_force_quote_style = false
ij_coffeescript_force_semicolon_style = false
ij_coffeescript_function_expression_brace_style = end_of_line
ij_coffeescript_import_merge_members = global
ij_coffeescript_import_prefer_absolute_path = global
ij_coffeescript_import_sort_members = true
ij_coffeescript_import_sort_module_name = false
ij_coffeescript_import_use_node_resolution = true
ij_coffeescript_imports_wrap = on_every_item
ij_coffeescript_indent_chained_calls = true
ij_coffeescript_indent_package_children = 0
ij_coffeescript_jsx_attribute_value = braces
ij_coffeescript_keep_blank_lines_in_code = 2
ij_coffeescript_keep_first_column_comment = true
ij_coffeescript_keep_indents_on_empty_lines = false
ij_coffeescript_keep_line_breaks = true
ij_coffeescript_keep_simple_methods_in_one_line = false
ij_coffeescript_method_parameters_new_line_after_left_paren = false
ij_coffeescript_method_parameters_right_paren_on_new_line = false
ij_coffeescript_method_parameters_wrap = off
ij_coffeescript_object_literal_wrap = on_every_item
ij_coffeescript_prefer_as_type_cast = false
ij_coffeescript_reformat_c_style_comments = false
ij_coffeescript_space_after_comma = true
ij_coffeescript_space_after_dots_in_rest_parameter = false
ij_coffeescript_space_after_generator_mult = true
ij_coffeescript_space_after_property_colon = true
ij_coffeescript_space_after_type_colon = true
ij_coffeescript_space_after_unary_not = false
ij_coffeescript_space_before_async_arrow_lparen = true
ij_coffeescript_space_before_class_lbrace = true
ij_coffeescript_space_before_comma = false
ij_coffeescript_space_before_function_left_parenth = true
ij_coffeescript_space_before_generator_mult = false
ij_coffeescript_space_before_property_colon = false
ij_coffeescript_space_before_type_colon = false
ij_coffeescript_space_before_unary_not = false
ij_coffeescript_spaces_around_additive_operators = true
ij_coffeescript_spaces_around_arrow_function_operator = true
ij_coffeescript_spaces_around_assignment_operators = true
ij_coffeescript_spaces_around_bitwise_operators = true
ij_coffeescript_spaces_around_equality_operators = true
ij_coffeescript_spaces_around_logical_operators = true
ij_coffeescript_spaces_around_multiplicative_operators = true
ij_coffeescript_spaces_around_relational_operators = true
ij_coffeescript_spaces_around_shift_operators = true
ij_coffeescript_spaces_around_unary_operator = false
ij_coffeescript_spaces_within_array_initializer_braces = false
ij_coffeescript_spaces_within_array_initializer_brackets = false
ij_coffeescript_spaces_within_imports = false
ij_coffeescript_spaces_within_index_brackets = false
ij_coffeescript_spaces_within_interpolation_expressions = false
ij_coffeescript_spaces_within_method_call_parentheses = false
ij_coffeescript_spaces_within_method_parentheses = false
ij_coffeescript_spaces_within_object_braces = false
ij_coffeescript_spaces_within_object_literal_braces = false
ij_coffeescript_spaces_within_object_type_braces = true
ij_coffeescript_spaces_within_range_brackets = false
ij_coffeescript_spaces_within_type_assertion = false
ij_coffeescript_spaces_within_union_types = true
ij_coffeescript_union_types_wrap = on_every_item
ij_coffeescript_use_chained_calls_group_indents = false
ij_coffeescript_use_double_quotes = true
ij_coffeescript_use_explicit_js_extension = global
ij_coffeescript_use_path_mapping = always
ij_coffeescript_use_public_modifier = false
ij_coffeescript_use_semicolon_after_statement = false
ij_coffeescript_var_declaration_wrap = normal
[{*.erb,*.rhtml}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_rhtml_keep_indents_on_empty_lines = false
[{*.js,*.cjs}]
ij_continuation_indent_size = 2
ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = false
ij_javascript_align_multiline_binary_operation = false
ij_javascript_align_multiline_chained_methods = false
ij_javascript_align_multiline_extends_list = false
ij_javascript_align_multiline_for = true
ij_javascript_align_multiline_parameters = true
ij_javascript_align_multiline_parameters_in_calls = false
ij_javascript_align_multiline_ternary_operation = false
ij_javascript_align_object_properties = 0
ij_javascript_align_union_types = false
ij_javascript_align_var_statements = 0
ij_javascript_array_initializer_new_line_after_left_brace = false
ij_javascript_array_initializer_right_brace_on_new_line = false
ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**/*,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = end_of_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
ij_javascript_force_quote_style = false
ij_javascript_force_semicolon_style = false
ij_javascript_function_expression_brace_style = end_of_line
ij_javascript_if_brace_force = never
ij_javascript_import_merge_members = global
ij_javascript_import_prefer_absolute_path = global
ij_javascript_import_sort_members = true
ij_javascript_import_sort_module_name = false
ij_javascript_import_use_node_resolution = true
ij_javascript_imports_wrap = on_every_item
ij_javascript_indent_case_from_switch = true
ij_javascript_indent_chained_calls = true
ij_javascript_indent_package_children = 0
ij_javascript_jsx_attribute_value = braces
ij_javascript_keep_blank_lines_in_code = 2
ij_javascript_keep_first_column_comment = true
ij_javascript_keep_indents_on_empty_lines = false
ij_javascript_keep_line_breaks = true
ij_javascript_keep_simple_blocks_in_one_line = false
ij_javascript_keep_simple_methods_in_one_line = false
ij_javascript_line_comment_add_space = true
ij_javascript_line_comment_at_first_column = false
ij_javascript_method_brace_style = end_of_line
ij_javascript_method_call_chain_wrap = off
ij_javascript_method_parameters_new_line_after_left_paren = false
ij_javascript_method_parameters_right_paren_on_new_line = false
ij_javascript_method_parameters_wrap = off
ij_javascript_object_literal_wrap = on_every_item
ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
ij_javascript_space_after_comma = true
ij_javascript_space_after_dots_in_rest_parameter = false
ij_javascript_space_after_generator_mult = true
ij_javascript_space_after_property_colon = true
ij_javascript_space_after_quest = true
ij_javascript_space_after_type_colon = true
ij_javascript_space_after_unary_not = false
ij_javascript_space_before_async_arrow_lparen = true
ij_javascript_space_before_catch_keyword = true
ij_javascript_space_before_catch_left_brace = true
ij_javascript_space_before_catch_parentheses = true
ij_javascript_space_before_class_lbrace = true
ij_javascript_space_before_class_left_brace = true
ij_javascript_space_before_colon = true
ij_javascript_space_before_comma = false
ij_javascript_space_before_do_left_brace = true
ij_javascript_space_before_else_keyword = true
ij_javascript_space_before_else_left_brace = true
ij_javascript_space_before_finally_keyword = true
ij_javascript_space_before_finally_left_brace = true
ij_javascript_space_before_for_left_brace = true
ij_javascript_space_before_for_parentheses = true
ij_javascript_space_before_for_semicolon = false
ij_javascript_space_before_function_left_parenth = true
ij_javascript_space_before_generator_mult = false
ij_javascript_space_before_if_left_brace = true
ij_javascript_space_before_if_parentheses = true
ij_javascript_space_before_method_call_parentheses = false
ij_javascript_space_before_method_left_brace = true
ij_javascript_space_before_method_parentheses = false
ij_javascript_space_before_property_colon = false
ij_javascript_space_before_quest = true
ij_javascript_space_before_switch_left_brace = true
ij_javascript_space_before_switch_parentheses = true
ij_javascript_space_before_try_left_brace = true
ij_javascript_space_before_type_colon = false
ij_javascript_space_before_unary_not = false
ij_javascript_space_before_while_keyword = true
ij_javascript_space_before_while_left_brace = true
ij_javascript_space_before_while_parentheses = true
ij_javascript_spaces_around_additive_operators = true
ij_javascript_spaces_around_arrow_function_operator = true
ij_javascript_spaces_around_assignment_operators = true
ij_javascript_spaces_around_bitwise_operators = true
ij_javascript_spaces_around_equality_operators = true
ij_javascript_spaces_around_logical_operators = true
ij_javascript_spaces_around_multiplicative_operators = true
ij_javascript_spaces_around_relational_operators = true
ij_javascript_spaces_around_shift_operators = true
ij_javascript_spaces_around_unary_operator = false
ij_javascript_spaces_within_array_initializer_brackets = false
ij_javascript_spaces_within_brackets = false
ij_javascript_spaces_within_catch_parentheses = false
ij_javascript_spaces_within_for_parentheses = false
ij_javascript_spaces_within_if_parentheses = false
ij_javascript_spaces_within_imports = false
ij_javascript_spaces_within_interpolation_expressions = false
ij_javascript_spaces_within_method_call_parentheses = false
ij_javascript_spaces_within_method_parentheses = false
ij_javascript_spaces_within_object_literal_braces = false
ij_javascript_spaces_within_object_type_braces = true
ij_javascript_spaces_within_parentheses = false
ij_javascript_spaces_within_switch_parentheses = false
ij_javascript_spaces_within_type_assertion = false
ij_javascript_spaces_within_union_types = true
ij_javascript_spaces_within_while_parentheses = false
ij_javascript_special_else_if_treatment = true
ij_javascript_ternary_operation_signs_on_next_line = false
ij_javascript_ternary_operation_wrap = off
ij_javascript_union_types_wrap = on_every_item
ij_javascript_use_chained_calls_group_indents = false
ij_javascript_use_double_quotes = true
ij_javascript_use_explicit_js_extension = global
ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.sht,*.html,*.shtm,*.shtml,*.htm,*.ng}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
[{*.xslt,*.rng,*.xsl,*.xml,*.jhm,*.tld,*.xsd,*.fxml,*.wsdl,*.jrxml,*.jnlp,*.ant,*.xul}]
indent_size = 2
ij_xml_block_comment_at_first_column = true
ij_xml_keep_indents_on_empty_lines = false
ij_xml_line_comment_at_first_column = true
[{*.yml.example,*.yml,*.yaml}]
indent_size = 2
ij_continuation_indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
[{*.zsh,*.bash,*.sh}]
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{.babelrc,.stylelintrc,.eslintrc,jest.config,*.json,*.jsb3,*.jsb2,*.bowerrc}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{rcov,spec,rake,cucumber,rails,spork,capfile,gemfile,rakefile,guardfile,isolate,vagrantfile,Puppetfile,*.jbuilder,*.rbw,*.gemspec,*.thor,*.ru,*.rb,*.rake}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_ruby_align_group_field_declarations = false
ij_ruby_align_multiline_parameters = true
ij_ruby_blank_lines_around_method = 1
ij_ruby_convert_brace_block_by_enter = true
ij_ruby_force_newlines_around_visibility_mods = true
ij_ruby_indent_private_methods = false
ij_ruby_indent_protected_methods = false
ij_ruby_indent_public_methods = false
ij_ruby_indent_when_cases = false
ij_ruby_keep_blank_lines_in_declarations = 2
ij_ruby_keep_indents_on_empty_lines = false
ij_ruby_keep_line_breaks = true
ij_ruby_parentheses_around_method_arguments = true
ij_ruby_spaces_around_hashrocket = true
ij_ruby_spaces_around_other_operators = true
ij_ruby_spaces_around_range_operators = false
ij_ruby_spaces_around_relational_operators = true
ij_ruby_spaces_within_array_initializer_braces = true
ij_ruby_spaces_within_braces = false
[{version-autocompleter.component.ts,*.ats,*.ts}]
ij_continuation_indent_size = 2
ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false
ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**/*,@angular/material,@angular/material/typings/**
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
ij_typescript_blank_lines_around_field_in_interface = 0
ij_typescript_blank_lines_around_function = 1
ij_typescript_blank_lines_around_method = 1
ij_typescript_blank_lines_around_method_in_interface = 1
ij_typescript_block_brace_style = end_of_line
ij_typescript_call_parameters_new_line_after_left_paren = false
ij_typescript_call_parameters_right_paren_on_new_line = false
ij_typescript_call_parameters_wrap = off
ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never
ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = keep
ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never
ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = false
ij_typescript_force_semicolon_style = false
ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never
ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 2
ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true
ij_typescript_keep_simple_blocks_in_one_line = false
ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off
ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item
ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false
ij_typescript_prefer_as_type_cast = false
ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false
ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false
ij_typescript_space_after_generator_mult = true
ij_typescript_space_after_property_colon = true
ij_typescript_space_after_quest = true
ij_typescript_space_after_type_colon = false
ij_typescript_space_after_unary_not = false
ij_typescript_space_before_async_arrow_lparen = true
ij_typescript_space_before_catch_keyword = true
ij_typescript_space_before_catch_left_brace = true
ij_typescript_space_before_catch_parentheses = true
ij_typescript_space_before_class_lbrace = true
ij_typescript_space_before_class_left_brace = true
ij_typescript_space_before_colon = true
ij_typescript_space_before_comma = false
ij_typescript_space_before_do_left_brace = true
ij_typescript_space_before_else_keyword = true
ij_typescript_space_before_else_left_brace = true
ij_typescript_space_before_finally_keyword = true
ij_typescript_space_before_finally_left_brace = true
ij_typescript_space_before_for_left_brace = true
ij_typescript_space_before_for_parentheses = true
ij_typescript_space_before_for_semicolon = false
ij_typescript_space_before_function_left_parenth = true
ij_typescript_space_before_generator_mult = false
ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true
ij_typescript_space_before_switch_parentheses = true
ij_typescript_space_before_try_left_brace = true
ij_typescript_space_before_type_colon = false
ij_typescript_space_before_unary_not = false
ij_typescript_space_before_while_keyword = true
ij_typescript_space_before_while_left_brace = true
ij_typescript_space_before_while_parentheses = true
ij_typescript_spaces_around_additive_operators = true
ij_typescript_spaces_around_arrow_function_operator = true
ij_typescript_spaces_around_assignment_operators = true
ij_typescript_spaces_around_bitwise_operators = true
ij_typescript_spaces_around_equality_operators = true
ij_typescript_spaces_around_logical_operators = true
ij_typescript_spaces_around_multiplicative_operators = true
ij_typescript_spaces_around_relational_operators = true
ij_typescript_spaces_around_shift_operators = true
ij_typescript_spaces_around_unary_operator = false
ij_typescript_spaces_within_array_initializer_brackets = false
ij_typescript_spaces_within_brackets = false
ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = false
ij_typescript_spaces_within_interpolation_expressions = false
ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = false
ij_typescript_spaces_within_object_type_braces = true
ij_typescript_spaces_within_parentheses = false
ij_typescript_spaces_within_switch_parentheses = false
ij_typescript_spaces_within_type_assertion = false
ij_typescript_spaces_within_union_types = false
ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = true
ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = true
ij_typescript_var_declaration_wrap = normal
ij_typescript_while_brace_force = never
ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false

@ -5,7 +5,9 @@ fail("jasmine fdescribe left in tests") if `grep --include '*.spec.ts' -rP 'fdes
git.modified_files
.select { |path| path.include?('frontend') && path.end_with?('.ts') }
.each do |path|
lines = File.readlines(path)
next unless File.readable?(path)
lines = File.readlines (path)
# Ignore non component files
component_line = lines.grep(/@Component/)[0]

@ -6,7 +6,7 @@
'showSkip': false,
'nextButton': {text: I18n.t('js.onboarding.buttons.next')},
onNext: function () {
$(".wp-table--cell-span.id a ")[0].click();
$(".inline-edit--display-field.id a ")[0].click();
}
},
{

@ -67,8 +67,8 @@
<div class="attributes-key-value">
<div class="attributes-key-value--key">Assignee</div>
<div class="attributes-key-value--value-container">
<div class="wp-edit-field--container">
<span class="wp-table--cell-span wp-edit-field--display-field inplace-edit wp-edit-field -editable" title="Jane Doe">Jane Doe</span>
<div class="inline-edit--container">
<span class="inline-edit--display-field inline-edit--display-field inplace-edit -editable" title="Jane Doe">Jane Doe</span>
</div>
</div>
<div class="attributes-key-value--key">
@ -81,8 +81,8 @@
</attribute-help-text>
</div>
<div class="attributes-key-value--value-container">
<div class="wp-edit-field--container">
<span class="wp-table--cell-span wp-edit-field--display-field inplace-edit wp-edit-field -editable" title="John Doe">John Doe</span>
<div class="inline-edit--container">
<span class="inline-edit--display-field inline-edit--display-field inplace-edit -editable" title="John Doe">John Doe</span>
</div>
</div>
</div>
@ -98,8 +98,8 @@
<div class="attributes-key-value">
<div class="attributes-key-value--key">Progress (%)</div>
<div class="attributes-key-value--value-container">
<div class="wp-edit-field--container">
<span title="-" class="wp-table--cell-span wp-edit-field--display-field inplace-edit wp-edit-field -placeholder -editable">
<div class="inline-edit--container">
<span title="-" class="inline-edit--display-field inline-edit--display-field inplace-edit -placeholder -editable">
<span style="width: 80px" class="progress-bar">
<span style="width: 60%" class="inner-progress closed"></span>
<span style="width: 0%" class="inner-progress done"></span>
@ -110,18 +110,18 @@
</div>
<div class="attributes-key-value--key">Date</div>
<div class="attributes-key-value--value-container">
<div class="wp-edit-field--container">
<span class="wp-table--cell-span wp-edit-field--display-field inplace-edit wp-edit-field -editable" title="12/06/2018">12/06/2018</span>
<div class="inline-edit--container">
<span class="inline-edit--display-field inline-edit--display-field inplace-edit -editable" title="12/06/2018">12/06/2018</span>
</div>
<span class="attributes-key-value--value-separator"></span>
<div class="wp-edit-field--container">
<span class="wp-table--cell-span wp-edit-field--display-field inplace-edit wp-edit-field -placeholder -editable">no end date</span>
<div class="inline-edit--container">
<span class="inline-edit--display-field inline-edit--display-field inplace-edit -placeholder -editable">no end date</span>
</div>
</div>
<div class="attributes-key-value--key">Priority</div>
<div class="attributes-key-value--value-container">
<div class="wp-edit-field--container">
<span class="wp-table--cell-span wp-edit-field--display-field inplace-edit wp-edit-field -editable" title="Normal">Normal</span>
<div class="inline-edit--container">
<span class="inline-edit--display-field inline-edit--display-field inplace-edit -editable" title="Normal">Normal</span>
</div>
</div>
</div>
@ -153,7 +153,7 @@
<a href="">Task: Fix bug (#34)</a>
</div>
<div class="grid-content collapse">
<span class="wp-table--cell-span inplace-edit wp-edit-field -editable" title="new">new</span>
<span class="inline-edit--display-field inplace-edit -editable" title="new">new</span>
</div>
<div class="grid-content collapse wp-relations-controls-section">
<a href="" title="Set or update description of this relation">

@ -35,13 +35,13 @@
Custom Field
</div>
<div class="attributes-key-value--value-container">
<wp-edit-field class="wp-edit-field--text">
<div class="wp-edit-field--container -small">
<span title="Editable text field" class="wp-table--cell-span inplace-edit -editable">
<editable-attribute-field>
<div class="inline-edit--container -small">
<span title="Editable text field" class="inline-edit--display-field inplace-edit -editable">
Editable text field
</span>
</div>
</wp-edit-field>
</editable-attribute-field>
</div>
</div>
</div>
@ -56,11 +56,9 @@
<div class="inplace-edit--read">
<accessible-by-keyboard class="inplace-editing--trigger-container">
<a href="" class="inplace-editing--trigger-link">
<span class="inplace-editing--container wp-edit-field--display-field">
<span class="inplace-edit--read-value -default">
<span>Comment and type @ to notify other people</span>
</span>
<span class="inplace-edit--icon-wrapper">
<span class="inplace-editing--container inline-edit--display-field">
<span>Comment and type @ to notify other people</span>
<span class="inplace-editing--trigger-icon">
<op-icon class="op-icon--wrapper">
<i aria-hidden="true" class="icon-edit" title="Comment and type @ to notify other people"></i>
</op-icon>
@ -86,10 +84,10 @@
</div>
</div>
</div>
<wp-edit-field>
<div class="wp-edit-field--container description -no-label">
<editable-attribute-field>
<div class="inline-edit--container description -no-label">
<div>
<span class="wp-table--cell-span inplace-edit -editable">
<span class="inline-edit--display-field inplace-edit -editable">
<div class="read-value--html wiki highlight -multiline">
<p>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
@ -100,7 +98,7 @@
</span>
</div>
</div>
</wp-edit-field>
</editable-attribute-field>
</div>
```

@ -42,7 +42,6 @@
// Specific field styles
@import work_packages/inplace_editing/display_fields
@import work_packages/inplace_editing/edit_fields
@import work_packages/inplace_editing/legacy_inplace_styles
@import work_packages/inplace_editing/textareas
// WP single view styles

@ -90,20 +90,20 @@
<a href="#">1234</a>
</td>
<td>
<span class="wp-table--cell-span -editable">Lorem ipsum</span>
<span class="inline-edit--display-field -editable">Lorem ipsum</span>
</td>
<td>
<span class="wp-table--cell-span -editable">User Story</span>
<span class="inline-edit--display-field -editable">User Story</span>
<div class="active-column"></div>
</td>
<td>
<span class="wp-table--cell-span -editable">In Progress</span>
<span class="inline-edit--display-field -editable">In Progress</span>
</td>
<td>
<span class="wp-table--cell-span -editable">Normal</span>
<span class="inline-edit--display-field -editable">Normal</span>
</td>
<td>
<span class="wp-table--cell-span -editable">John Doe</span>
<span class="inline-edit--display-field -editable">John Doe</span>
</td>
<td class="wp-table--context-menu-td">
<span>
@ -121,20 +121,20 @@
<a href="#">1234</a>
</td>
<td>
<span class="wp-table--cell-span -editable">Lorem ipsum</span>
<span class="inline-edit--display-field -editable">Lorem ipsum</span>
</td>
<td>
<span class="wp-table--cell-span -editable">User Story</span>
<span class="inline-edit--display-field -editable">User Story</span>
<div class="active-column"></div>
</td>
<td>
<span class="wp-table--cell-span -editable">In Progress</span>
<span class="inline-edit--display-field -editable">In Progress</span>
</td>
<td>
<span class="wp-table--cell-span -editable">Normal</span>
<span class="inline-edit--display-field -editable">Normal</span>
</td>
<td>
<span class="wp-table--cell-span -editable">John Doe</span>
<span class="inline-edit--display-field -editable">John Doe</span>
</td>
<td class="wp-table--context-menu-td">
<span>

@ -63,7 +63,7 @@
line-height: 24px
// Avoid that the select field gets too small
.wp-inline-edit--field.ng-select
.inline-edit--field.ng-select
min-width: 140px
// Styles for inline editable attributes
@ -71,7 +71,7 @@
display: table-cell
width: auto
&:hover .wp-edit-field.-error:hover
&:hover .inline-edit--active-field.-error:hover
border-color: $nm-color-error-border
//
@ -125,23 +125,16 @@ html:not(.-browser-mobile)
.wp-table--cell-td.-editing &
display: block
.inplace-edit
.inline-edit--display-field
display: initial
&.id .inplace-edit
// pointer-events: none
a
pointer-events: all
// Some padding for the inner cells of the display fields
.wp-table--cell-span
.inline-edit--display-field
padding: 2px
body.-browser-edge
// Ensure height is set in table
.work-package-table .wp-table--cell-span
.work-package-table .inline-edit--display-field
height: 22px !important
line-height: 22px !important

@ -42,7 +42,7 @@
&:hover
background: darken(#BEF3CA, 5%) !important
.wp-table--cell-span:hover
.inline-edit--display-field:hover
border-color: #35c53f
.wp-table--cancel-create-td

@ -27,7 +27,7 @@
//++
// READ value of edit fields
.wp-edit-field--display-field
.inline-edit--display-field
display: inline-block
max-width: 100%
@include text-shortener
@ -36,6 +36,11 @@
&.-placeholder
font-style: italic
// Always render custom options as inline
// when only one line
.custom-option:not(.-multiple-lines)
display: inline
&.split-time-field
white-space: nowrap
@ -58,6 +63,28 @@
font-style: italic
font-weight: bold
.wp-edit-field--text,
wp-edit-field
// Editable fields cursor
.inline-edit--display-field.-editable
cursor: text
border-color: transparent
border-style: solid
border-radius: 2px
border-width: 1px
line-height: normal
&:hover,
&:focus
border-color: $inplace-edit--border-color
&.-multiline
white-space: inherit
// Mark focused, non-editable read-values
.inline-edit--display-field:not(.id).-read-only
&:focus, &:hover
color: $inplace-edit--color--disabled
background: $inplace-edit--bg-color--disabled
cursor: not-allowed
editable-attribute-field
width: 100%

@ -1,8 +1,8 @@
.wp-edit-field
.inline-edit--container
&.-error,
.wp-table--cell-td.-error &
.wp-table--cell-span,
.wp-inline-edit--field
.inline-edit--display-field,
.inline-edit--field
background: $nm-color-error-background
border-color: $nm-color-error-border
@ -27,15 +27,6 @@
border-radius: 2px
border-color: darkblue
.inplace-edit--read-value
&:before
vertical-align: middle
.wp-table--cell-span
vertical-align: middle
&.inplace-edit .custom-option:not(.-multiple-lines)
display: inline
.inline-label
.form-label,
.icon-context:before
@ -43,11 +34,8 @@
// Style no-label fields (long text, description, ..) with padding
.wp-edit-field--container.-no-label:not(.-active)
.wp-table--cell-span
.inline-edit--container.-no-label:not(.-active)
.inline-edit--display-field
display: block
padding: 5px
padding-right: 0
padding: 5px 0 5px 5px
.wp-edit-field.description.-no-label
margin-left: -0.375rem

@ -1,160 +0,0 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2017 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See docs/COPYRIGHT.rdoc for more details.
//++
// *** NOTE ***
// Following code handles trigger-links and inplace icons
// It is used for example for the attachements list and comment form
// need to specify the a explicitly as otherwise
// the default class will win
a.inplace-editing--trigger-link,
.inplace-editing--trigger-link,
&:hover,
&:focus,
&.-focus
text-decoration: none
color: $body-font-color
.inplace-editing--container,
.wp-edit-field
border-color: $inplace-edit--border-color
&.-active
border-color: transparent
.inplace-edit--icon-wrapper
visibility: visible
.inplace-edit--read-value
display: inline-block
span
line-height: 2
.inplace-editing--container
position: relative
.work-package--details--long-field
.inplace-edit--read .inplace-edit--read-value
// Use the whole space and leave room for the icon on the right
width: calc(100% - 42px)
padding: 3px
line-height: 2
span.deleting
opacity: 0.5
img.avatar-mini
float: inherit
.inplace-edit--icon-wrapper
position: absolute
height: 100%
right: 0
text-align: center
width: 32px
background: $gray-light
border-left: 1px solid $inplace-edit--border-color
color: $body-font-color
visibility: hidden
i
position: relative
// Position the icon in the middle
top: calc(50% - 0.5rem)
.icon-context:before
// HACK: overriding default padding here
padding-right: 0
&:hover
text-decoration: none
// Editable fields cursor
.-editable .wp-table--cell-span,
.wp-table--cell-span.-editable
cursor: text
border-color: transparent
border-style: solid
border-radius: 2px
border-width: 1px
line-height: normal
&:hover,
&:focus
border-color: $inplace-edit--border-color
.work-package--placeholder
padding: 0 10px 0 0px
.inplace-edit--read-value--value-span
width: 100%
white-space: nowrap
&.-multiline
white-space: inherit
// Do not hover trigger-link when element is read-only
.-read-only
.inplace-editing--trigger-link:hover .inplace-editing--container
border-color: transparent
// Mark focused, non-editable read-values
.inplace-edit--read-value.-read-only,
.wp-table--cell-span:not(.id).-read-only
&:focus, &:hover
color: $inplace-edit--color--disabled
background: $inplace-edit--bg-color--disabled
cursor: not-allowed
// Animations on leaving work packages
.wp--row.-animated-leave
&.ng-leave
-webkit-transition: all 1s ease-in-out
-moz-transition: all 1s ease-in-out
-o-transition: all 1s ease-in-out
transition: all 1s ease-in-out
&.ng-leave-active
height: 0
line-height: 0
opacity: 0
// Allow horizontal scrolling in descripton field
.work-packages--details--description .wp-table--cell-span .inplace-edit--read-value--value-span
overflow-x: auto
// Style the attachment hint label of the description field
.wp-edit-field-attachment-label
// Reduce width due to save|cancel controls
width: 75%
position: absolute
left: 1px
font-size: 0.8rem
padding-top: 5px
font-style: italic

@ -10,7 +10,7 @@
// Capitalize status name
.work-packages--status-selector
.wp-edit-field--display-field
.inline-edit--display-field
text-transform: capitalize
// Full screen toggle indicator on the

@ -9,16 +9,16 @@
margin-left: 5px
// Fix display left padding of tpye
.wp-edit-field--display-field
.inline-edit--display-field
padding-left: 0 !important
// Disable text decoration from toolbar span
.wp-edit-field--display-field:hover
.inline-edit--display-field:hover
text-decoration: none
.wp-new-top-row--status,
.wp-new-top-row--type
.wp-inline-edit--field
.inline-edit--field
min-width: 125px
.work-packages--type-selector,

@ -1,3 +1,31 @@
// Add a border at all times to the inplace container
.inplace-editing--container
position: relative
// need to specify the a explicitly as otherwise
// the default class will win
a.inplace-editing--trigger-link,
.inplace-editing--trigger-link,
&:hover,
&:focus,
&.-focus
text-decoration: none
color: $body-font-color
&.-active
border-color: transparent
.inplace-editing--container
border-color: $inplace-edit--border-color
.inplace-editing--trigger-icon
visibility: visible
// Do not hover trigger-link when element is read-only
.-read-only
.inplace-editing--trigger-link:hover .inplace-editing--container
border-color: transparent
// Explicit styles for input-esque trigger appearance
.work-packages--activity--add-comment,
.work-package--watchers-lookup
@ -15,29 +43,34 @@
color: $body-font-color
font-style: italic
.inplace-edit--read-value
padding-left: 5px
// Editing existing comments
.comments-form
float: left
width: 100%
margin: 10px 0 100px 0
textarea
border: 1px solid #dddddd
padding: 8px
border-radius: 2px
font-size: 0.8125rem
width: 100%
button
float: right
font-size: 0.8125rem
background: linear-gradient(to bottom, white 0%, #eeeeee 74%, #eeeeee 100%) repeat scroll 0 0 rgba(0, 0, 0, 0)
border: 1px solid #CCCCCC
border-radius: 2px
color: #222222
margin: 10px 0 0 0
padding: 4px 10px 2px
cursor: pointer
height: 32px
// The trigger text left to the edit icon
.inplace-editing--trigger-text
width: calc(100% - 42px)
padding: 3px
line-height: 2
display: inline-block
// The edit icon to the right of the trigger text
.inplace-editing--trigger-icon
position: absolute
height: 100%
top: 0
right: 0
text-align: center
width: 32px
background: $gray-light
border-left: 1px solid $inplace-edit--border-color
color: $body-font-color
visibility: hidden
i
position: relative
// Position the icon in the middle
top: calc(50% - 0.5rem)
.icon-context:before
// HACK: overriding default padding here
padding-right: 0
&:hover
text-decoration: none

@ -33,8 +33,8 @@
// Subject field
.subject-header,
.wp-new--subject-wrapper
.wp-inline-edit--active-field.subject
.wp-inline-edit--field
.inline-edit--active-field.subject
.inline-edit--field
height: 40px
font-size: 16px
line-height: 1

@ -61,11 +61,11 @@
.description-section
border: 1px dotted lightblue
padding: 4px
.wp-edit-field
.inline-edit--container
@include text-shortener
// Similar to inner span's line-height
line-height: 1.6em
.wp-table--cell-span
.inline-edit--display-field
vertical-align: middle
.controls-container
text-align: right

@ -89,7 +89,7 @@ body.router--work-packages-split-view-new
// Fix height of subject row
.work-packages--subject-element,
.work-packages--details--subject .wp-inline-edit--field
.work-packages--details--subject .inline-edit--field
font-size: 1.125rem
font-weight: bold
@ -97,7 +97,7 @@ body.router--work-packages-split-view-new
line-height: 24px
overflow: hidden
.wp-inline-edit--field
.inline-edit--field
height: 38px
line-height: 36px

@ -172,26 +172,21 @@
width: 100%
margin: 0
.wp-table--cell-span
.inline-edit--display-field
white-space: normal
word-break: break-all
li.inline-edit
width: 100%
.inplace-edit--read-value
margin: 0
padding-top: 0
padding-bottom: 0
.work-packages--subject-element,
.work-packages--details--subject .wp-inline-edit--field
.work-packages--details--subject .inline-edit--field
font-size: 20px
font-weight: bold
line-height: 34px
.work-packages--subject-element
.wp-inline-edit--field
.inline-edit--field
height: 34px
// Style edit field to look like the display field.
@ -211,30 +206,24 @@
position: relative
// Fix: align and size hover border like buttons in toolbar.
.wp-edit-field.-no-label:not(.-active) .wp-table--cell-span
.inline-edit--container .inline-edit--display-field
padding-top: 3px
padding-bottom: 3px
margin-top: 2px
.work-packages--type-selector:not(.wp-new-top-row--element)
.wp-table--cell-span
.inline-edit--display-field
padding-right: 5px !important
// Remove left padding from type
.wp-edit-field--display-field
.inline-edit--display-field
padding-left: 0 !important
@media only screen and (min-width: 679px)
.wp-edit-field--container.-active
.inline-edit--container.-active
margin-right: 80px !important
width: 95%
.inplace-edit--read-value--value-span
white-space: nowrap
.inplace-edit--read-value--value-span:after
content: ':'
.edit-all-mode
.subject-header .work-packages--details--subject .inplace-edit--text-field
padding-left: 0.375rem

@ -86,9 +86,6 @@
.attributes-key-value--value-container
margin-bottom: 20px
.inplace-edit--read-value
padding: 0
.inplace-editing--container
border: none
@ -101,17 +98,9 @@
border-bottom: none
padding-top: 4px
// Reset margin for mobile, since the wiki toolbar is hidden on mobile
.inplace-edit.attribute-description
.inplace-edit--write
margin-top: 0
div[class*='work-packages--details--']
width: 100%
.inplace-edit--read-value span
white-space: normal
.work-package-details-activities-messages
font-size: 0.9rem

@ -122,7 +122,7 @@
margin-bottom: 0
// Overwrite "click to add description" placeholder with a simple dash.
.wp-edit-field.description.-placeholder
.inline-edit--active-field.description.-placeholder
.read-value--html
display: none
&:after

@ -160,9 +160,6 @@
> h4
margin-top: 5px
.inplace-edit--read-value
padding: 0.375rem 0.6rem
i
display: inline-block
&:before

@ -40,7 +40,7 @@ $table-timeline--compact-row-height: 28px
// Align with section header
.wp-table--table-header:first-child .generic-table--sort-header-outer,
.wp-table--cell-td:first-child .wp-edit-field--display-field,
.wp-table--cell-td:first-child .inline-edit--display-field,
.wp-inline-create--add-link i:before
padding-left: 0

@ -212,6 +212,14 @@ en:
general_text_No: "No"
general_text_Yes: "Yes"
hal:
error:
update_conflict_refresh: "Click here to refresh the resource and update to the newest version."
edit_prohibited: "Editing %{attribute} is blocked for this resource. Either this attribute is derived from relations (e.g, children) or otherwise not configurable."
format:
date: "%{attribute} is no valid date - YYYY-MM-DD expected."
general: "An error has occurred."
homescreen:
blocks:
new_features:
@ -299,6 +307,7 @@ en:
label_no_data: "No data to display"
label_no_due_date: "no end date"
label_no_start_date: "no start date"
label_no_value: "No value"
label_none: "none"
label_not_contains: "doesn't contain"
label_not_equals: "is not"
@ -660,12 +669,6 @@ en:
description_enter_text: "Enter text"
description_options_hide: "Hide options"
description_options_show: "Show options"
error:
update_conflict_refresh: "Click here to refresh the work package and update to the newest version."
edit_prohibited: "Editing %{attribute} is blocked for this work package. Either this attribute is derived from relations (e.g, children) or otherwise not configurable."
format:
date: "%{attribute} is no valid date - YYYY-MM-DD expected."
general: "An error has occurred."
edit_attribute: "%{attribute} - Edit"
key_value: "%{key}: %{value}"
label_enable_multi_select: "Enable multiselect"
@ -680,7 +683,6 @@ en:
message_view_spent_time: "Show spent time for this work package"
message_work_package_read_only: "Work package is locked in this status. No attribute other than status can be altered."
message_work_package_status_blocked: "Work package status is not writable due to closed status and closed version being assigned."
no_value: "No value"
placeholder_filter_by_text: "Subject, description, comments, ..."
inline_create:
title: 'Click here to add a new work package to this list'

@ -48,8 +48,8 @@ Let's take a look at the file structure of the costs folder `frontend/`:
module
├── main.ts
└── wp-display
├── wp-display-costs-by-type-field.module.ts
└── wp-display-currency-field.module.ts
├── costs-by-type-display-field.module.ts
└── currency-display-field.module.ts
```
The Angular frontend entry point is `frontend/module/main.ts` and should export a `PluginModule` ngModule that looks like the following:

@ -93,6 +93,7 @@ import {WpPreviewModal} from "core-components/modals/preview-modal/wp-preview-mo
import {PreviewTriggerService} from "core-app/globals/global-listeners/preview-trigger.service";
import {OpenprojectOverviewModule} from "core-app/modules/overview/openproject-overview.module";
import {OpenprojectMyPageModule} from "core-app/modules/my-page/openproject-my-page.module";
import {OpenprojectProjectsModule} from "core-app/modules/projects/openproject-projects.module";
@NgModule({
imports: [
@ -114,6 +115,9 @@ import {OpenprojectMyPageModule} from "core-app/modules/my-page/openproject-my-p
OpenprojectGridsModule,
OpenprojectAttachmentsModule,
// Project module
OpenprojectProjectsModule,
// Work packages and their routes
OpenprojectWorkPackagesModule,
OpenprojectWorkPackageRoutesModule,

@ -86,7 +86,7 @@ export class MainMenuToggleService {
}
// click on arrow or hamburger icon
public toggleNavigation(event?:JQuery.TriggeredEvent) : void {
public toggleNavigation(event?:JQuery.TriggeredEvent):void {
if (event) {
event.stopPropagation();
event.preventDefault();

@ -27,7 +27,7 @@
//++
import {States} from '../../states.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {OpModalComponent} from "core-components/op-modals/op-modal.component";
@ -67,7 +67,7 @@ export class SaveQueryModal extends OpModalComponent {
readonly states:States,
readonly querySpace:IsolatedQuerySpace,
readonly wpListService:WorkPackagesListService,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly halNotification:HalResourceNotificationService,
readonly cdRef:ChangeDetectorRef,
readonly notificationsService:NotificationsService) {
super(locals, cdRef, elementRef);
@ -105,7 +105,7 @@ export class SaveQueryModal extends OpModalComponent {
this.closeMe($event);
return Promise.resolve(true);
})
.catch((error:any) => this.wpNotificationsService.handleRawError(error))
.catch((error:any) => this.halNotification.handleRawError(error))
.then(() => this.isBusy = false); // Same as .finally()
}
}

@ -28,7 +28,7 @@
import {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {States} from '../../states.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {OpModalComponent} from "core-components/op-modals/op-modal.component";
@ -66,7 +66,7 @@ export class QuerySharingModal extends OpModalComponent implements OnInit {
readonly querySpace:IsolatedQuerySpace,
readonly cdRef:ChangeDetectorRef,
readonly wpListService:WorkPackagesListService,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly halNotification:HalResourceNotificationService,
readonly notificationsService:NotificationsService) {
super(locals, cdRef, elementRef);
}

@ -28,7 +28,7 @@
import {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {States} from '../../states.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {OpModalComponent} from "core-components/op-modals/op-modal.component";
import {ChangeDetectorRef, Component, ElementRef, Inject, OnInit} from "@angular/core";
@ -40,6 +40,7 @@ import {StateService} from '@uirouter/core';
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {WorkPackageService} from "core-components/work-packages/work-package.service";
import {BackRoutingService} from "core-app/modules/common/back-routing/back-routing.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
templateUrl: './wp-destroy.modal.html'
@ -76,8 +77,7 @@ export class WpDestroyModal extends OpModalComponent implements OnInit {
readonly states:States,
readonly wpTableFocus:WorkPackageViewFocusService,
readonly wpListService:WorkPackagesListService,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly notificationsService:NotificationsService,
readonly notificationService:WorkPackageNotificationService,
readonly backRoutingService:BackRoutingService) {
super(locals, cdRef, elementRef);
}

@ -29,7 +29,8 @@
import {OPContextMenuService} from "core-components/op-context-menu/op-context-menu.service";
import {Directive, ElementRef, Inject} from "@angular/core";
import {OpContextMenuTrigger} from "core-components/op-context-menu/handlers/op-context-menu-trigger.directive";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {States} from "core-components/states.service";
import {FormResource} from 'core-app/modules/hal/resources/form-resource';
@ -41,7 +42,7 @@ export class WorkPackageCreateSettingsMenuDirective extends OpContextMenuTrigger
constructor(readonly elementRef:ElementRef,
readonly opContextMenu:OPContextMenuService,
readonly states:States,
readonly wpEditing:WorkPackageEditingService) {
readonly halEditing:HalResourceEditingService) {
super(elementRef, opContextMenu);
}
@ -50,7 +51,7 @@ export class WorkPackageCreateSettingsMenuDirective extends OpContextMenuTrigger
const wp = this.states.workPackages.get('new').value;
if (wp) {
const change = this.wpEditing.changeFor(wp);
const change = this.halEditing.changeFor(wp);
change.getForm().then(
(loadedForm:FormResource) => {
this.buildItems(loadedForm);

@ -30,15 +30,17 @@ import {StateService} from '@uirouter/core';
import {OPContextMenuService} from "core-components/op-context-menu/op-context-menu.service";
import {Directive, ElementRef, Inject, Input} from "@angular/core";
import {OpContextMenuTrigger} from "core-components/op-context-menu/handlers/op-context-menu-trigger.directive";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
import {CollectionResource} from 'core-app/modules/hal/resources/collection-resource';
import {Highlighting} from "core-components/wp-fast-table/builders/highlighting/highlighting.functions";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Directive({
selector: '[wpStatusDropdown]'
@ -49,17 +51,17 @@ export class WorkPackageStatusDropdownDirective extends OpContextMenuTrigger {
constructor(readonly elementRef:ElementRef,
readonly opContextMenu:OPContextMenuService,
readonly $state:StateService,
protected wpNotificationsService:WorkPackageNotificationService,
protected wpEditing:WorkPackageEditingService,
protected workPackageNotificationService:WorkPackageNotificationService,
protected halEditing:HalResourceEditingService,
protected notificationService:NotificationsService,
protected I18n:I18nService,
protected wpEvents:WorkPackageEventsService) {
protected halEvents:HalEventsService) {
super(elementRef, opContextMenu);
}
protected open(evt:JQuery.TriggeredEvent) {
const change = this.wpEditing.changeFor(this.workPackage);
const change = this.halEditing.changeFor(this.workPackage);
change.getForm().then((form:any) => {
const statuses = form.schema.status.allowedValues;
@ -82,15 +84,15 @@ export class WorkPackageStatusDropdownDirective extends OpContextMenuTrigger {
}
private updateStatus(status:HalResource) {
const change = this.wpEditing.changeFor(this.workPackage);
const change = this.halEditing.changeFor(this.workPackage);
change.projectedResource.status = status;
if (!this.workPackage.isNew) {
this.wpEditing
this.halEditing
.save(change)
.then(() => {
this.wpNotificationsService.showSave(this.workPackage);
this.wpEvents.push({ type: 'updated', id: this.workPackage.id! });
this.workPackageNotificationService.showSave(this.workPackage);
this.halEvents.push(this.workPackage, { eventType: 'updated' });
});
}
}

@ -32,11 +32,13 @@ import {StateCacheService} from '../states/state-cache.service';
import {Injectable} from '@angular/core';
import {ProjectResource} from 'core-app/modules/hal/resources/project-resource';
import {ProjectDmService} from 'core-app/modules/hal/dm-services/project-dm.service';
import {SchemaCacheService} from "core-components/schemas/schema-cache.service";
@Injectable()
export class ProjectCacheService extends StateCacheService<ProjectResource> {
constructor(readonly states:States,
readonly schemaCacheService:SchemaCacheService,
readonly projectDmService:ProjectDmService) {
super();
}
@ -47,8 +49,19 @@ export class ProjectCacheService extends StateCacheService<ProjectResource> {
.then(_ => undefined);
}
updateValue(id:string, val:ProjectResource) {
this.schemaCacheService.ensureLoaded(val).then(() => {
super.updateValue(id, val);
});
}
protected load(id:string):Promise<ProjectResource> {
return this.projectDmService.one(parseInt(id));
return this
.projectDmService
.one(parseInt(id))
.then((project) => {
return this.schemaCacheService.ensureLoaded(project).then(() => project);
});
}
protected get multiState():MultiInputState<ProjectResource> {

@ -1,7 +1,3 @@
import {Injectable} from '@angular/core';
import {SchemaResource} from 'core-app/modules/hal/resources/schema-resource';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
@ -31,6 +27,10 @@ import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.ser
// ++
import {InputState, State} from 'reactivestates';
import {States} from '../states.service';
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
import {Injectable} from '@angular/core';
import {SchemaResource} from 'core-app/modules/hal/resources/schema-resource';
import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
@Injectable()
export class SchemaCacheService {
@ -44,13 +44,13 @@ export class SchemaCacheService {
* @param href The schema's href.
* @return A promise with the loaded schema.
*/
ensureLoaded(workPackage:WorkPackageResource):Promise<unknown> {
const state = this.state(workPackage);
ensureLoaded(resource:HalResource):Promise<unknown> {
const state = this.state(resource);
if (state.hasValue()) {
return Promise.resolve(state.value);
} else {
return this.load(workPackage).valuesPromise() as Promise<unknown>;
return this.load(resource).valuesPromise() as Promise<unknown>;
}
}
@ -58,24 +58,29 @@ export class SchemaCacheService {
* Get the associated schema state of the work package
* without initializing a new resource.
*/
state(workPackage:WorkPackageResource):InputState<SchemaResource> {
const schema = workPackage.$links.schema;
state(resource:HalResource):InputState<SchemaResource> {
const schema = resource.$links.schema;
if (!schema) {
throw `Resource ${resource} has no schema!`;
}
return this.states.schemas.get(schema.href!);
}
/**
* Load the associated schema for the given work package, if needed.
*/
load(workPackage:WorkPackageResource, forceUpdate = false):State<SchemaResource> {
const state = this.state(workPackage);
load(resource:HalResource, forceUpdate = false):State<SchemaResource> {
const state = this.state(resource);
if (forceUpdate) {
state.clear();
}
state.putFromPromiseIfPristine(() => {
const resource = this.halResourceService.createLinkedResource(workPackage, 'schema', workPackage.$links.schema.$link);
return resource.$load() as any;
const schemaResource = this.halResourceService.createLinkedResource(resource, 'schema', resource.$links.schema.$link);
return schemaResource.$load() as any;
});
return state;

@ -66,6 +66,13 @@ export abstract class StateCacheService<T> {
return this.state(id).values$();
}
/**
* Observe the changes of the given id
*/
public changes$(id:string):Observable<T|undefined> {
return this.state(id).changes$();
}
/**
* Observe the entire set of loaded results
*/

@ -38,10 +38,14 @@ import {OpenProjectFileUploadService} from 'core-components/api/op-file-upload/o
import {SchemaCacheService} from 'core-components/schemas/schema-cache.service';
import {States} from 'core-components/states.service';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from 'core-components/wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {take, takeWhile} from 'rxjs/operators';
import {WorkPackageCreateService} from '../wp-new/wp-create.service';
import {WorkPackageDmService} from "core-app/modules/hal/dm-services/work-package-dm.service";
import {WorkPackagesActivityService} from "core-components/wp-single-view-tabs/activity-panel/wp-activity.service";
import {TimezoneService} from "core-components/datetime/timezone.service";
import {ConfigurationService} from "core-app/modules/common/config/configuration.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
describe('WorkPackageCacheService', () => {
let injector:Injector;
@ -58,14 +62,18 @@ describe('WorkPackageCacheService', () => {
providers: [
States,
HalResourceService,
TimezoneService,
WorkPackagesActivityService,
WorkPackageCacheService,
SchemaCacheService,
WorkPackageDmService,
{provide: ConfigurationService, useValue: {}},
{provide: PathHelperService, useValue: {}},
{provide: I18nService, useValue: {t: (...args:any[]) => 'translation'}},
{provide: WorkPackageResource, useValue: {}},
{provide: WorkPackageCreateService, useValue: {}},
{provide: NotificationsService, useValue: {}},
{provide: HalResourceNotificationService, useValue: {handleRawError: () => false}},
{provide: WorkPackageNotificationService, useValue: {}},
{provide: OpenProjectFileUploadService, useValue: {}}
]
@ -99,7 +107,7 @@ describe('WorkPackageCacheService', () => {
dummyWorkPackages = [workPackage1 as any];
});
it('returns a work package after the list has been initialized', function(done:any) {
it('returns a work package after the list has been initialized', function (done:any) {
wpCacheService.loadWorkPackage('1').values$()
.pipe(
take(1)

@ -6,7 +6,7 @@
<div class="work-package--details--long-field work-packages--activity--add-comment hide-when-print"
#commentContainer
*ngIf="canAddComment">
<div class="wp-edit-field inplace-edit">
<div class="inline-edit--container inplace-edit">
<edit-form-portal *ngIf="active"
[schemaInput]="schema"
[changeInput]="change"
@ -17,16 +17,16 @@
class="inplace-edit--read">
<accessible-by-keyboard
class="inplace-editing--trigger-container"
spanClass="inplace-editing--container wp-edit-field--display-field"
spanClass="inplace-editing--container inline-edit--display-field"
linkClass="inplace-editing--trigger-link"
[linkAriaLabel]="text.editTitle"
(execute)="activate()">
<span class="inplace-edit--read-value -default">
<span class="inplace-editing--trigger-text inline-edit--formattable-display-text -default">
<span [textContent]="text.placeholder"></span>
</span>
<span class="inplace-edit--icon-wrapper">
<span class="inplace-editing--trigger-icon">
<op-icon icon-classes="icon-edit" [icon-title]="text.editTitle"></op-icon>
</span>
</accessible-by-keyboard>

@ -28,7 +28,7 @@
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {ErrorResource} from 'core-app/modules/hal/resources/error-resource';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageCacheService} from '../work-package-cache.service';
import {WorkPackagesActivityService} from 'core-components/wp-single-view-tabs/activity-panel/wp-activity.service';
import {LoadingIndicatorService} from "core-app/modules/common/loading-indicator/loading-indicator.service";
@ -52,6 +52,7 @@ import {NotificationsService} from "core-app/modules/common/notifications/notifi
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {WorkPackageCommentFieldHandler} from "core-components/work-packages/work-package-comment/work-package-comment-field-handler";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
selector: 'work-package-comment',
@ -83,7 +84,7 @@ export class WorkPackageCommentComponent extends WorkPackageCommentFieldHandler
protected ConfigurationService:ConfigurationService,
protected loadingIndicator:LoadingIndicatorService,
protected wpCacheService:WorkPackageCacheService,
protected wpNotificationsService:WorkPackageNotificationService,
protected workPackageNotificationService:WorkPackageNotificationService,
protected NotificationsService:NotificationsService,
protected cdRef:ChangeDetectorRef,
protected I18n:I18nService) {
@ -164,7 +165,7 @@ export class WorkPackageCommentComponent extends WorkPackageCommentFieldHandler
.catch((error:any) => {
this.inFlight = false;
if (error instanceof ErrorResource) {
this.wpNotificationsService.showError(error, this.workPackage);
this.workPackageNotificationService.showError(error, this.workPackage);
}
else {
this.NotificationsService.addError(this.I18n.t('js.work_packages.comment_send_failed'));
@ -178,4 +179,8 @@ export class WorkPackageCommentComponent extends WorkPackageCommentFieldHandler
setTimeout(() => { scrollableContainer.scrollTop = scrollableContainer.scrollHeight; }, 400);
}
}
setErrors(newErrors:string[]):void {
// interface
}
}

@ -33,10 +33,7 @@ import {PathHelperService} from "core-app/modules/common/path-helper/path-helper
import {UrlParamsHelperService} from "core-components/wp-query/url-params-helper";
import {NotificationsService} from "core-app/modules/common/notifications/notifications.service";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {
WorkPackageDeletedEvent,
WorkPackageEventsService
} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalDeletedEvent, HalEventsService} from "core-app/modules/hal/services/hal-events.service";
@Injectable()
export class WorkPackageService {
@ -51,7 +48,7 @@ export class WorkPackageService {
private readonly UrlParamsHelper:UrlParamsHelperService,
private readonly NotificationsService:NotificationsService,
private readonly I18n:I18nService,
private readonly wpEvents:WorkPackageEventsService) {
private readonly halEvents:HalEventsService) {
}
public performBulkDelete(ids:string[], defaultHandling:boolean) {
@ -67,7 +64,7 @@ export class WorkPackageService {
.then(() => {
this.NotificationsService.addSuccess(this.text.successful_delete);
ids.forEach(id => this.wpEvents.push({ type: 'deleted', id: id } as WorkPackageDeletedEvent));
ids.forEach(id => this.halEvents.push({_type:'WorkPackage', id: id}, { eventType: 'deleted'} as HalDeletedEvent));
if (this.$state.includes('**.list.details.**')
&& ids.indexOf(this.$state.params.workPackageId) > -1) {

@ -29,8 +29,9 @@
import {Component, Input, EventEmitter, Output} from '@angular/core';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageRelationsHierarchyService} from 'core-app/components/wp-relations/wp-relations-hierarchy/wp-relations-hierarchy.service';
import {WorkPackageNotificationService} from 'core-app/components/wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
templateUrl: './wp-breadcrumb-parent.html',
@ -53,7 +54,7 @@ export class WorkPackageBreadcrumbParentComponent {
public constructor(
protected readonly I18n:I18nService,
protected readonly wpRelationsHierarchy:WorkPackageRelationsHierarchyService,
protected readonly wpNotifications:WorkPackageNotificationService
protected readonly notificationService:WorkPackageNotificationService
) {
}
@ -87,7 +88,7 @@ export class WorkPackageBreadcrumbParentComponent {
this.isSaving = true;
this.wpRelationsHierarchy.changeParent(this.workPackage, newParentId)
.catch((error:any) => {
this.wpNotifications.handleRawError(error, this.workPackage);
this.notificationService.handleRawError(error, this.workPackage);
})
.then(() => this.isSaving = false); // Behaves as .finally()
}

@ -44,7 +44,8 @@ import {debugLog} from '../../../helpers/debug_output';
import {CurrentProjectService} from '../../projects/current-project.service';
import {States} from '../../states.service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageCacheService} from '../work-package-cache.service';
import {input, InputState} from 'reactivestates';
import {DisplayFieldService} from 'core-app/modules/fields/display/display-field.service';
@ -142,7 +143,7 @@ export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
protected currentProject:CurrentProjectService,
protected PathHelper:PathHelperService,
protected states:States,
protected wpEditing:WorkPackageEditingService,
protected halEditing:HalResourceEditingService,
protected halResourceService:HalResourceService,
protected displayFieldService:DisplayFieldService,
protected wpCacheService:WorkPackageCacheService,
@ -157,7 +158,7 @@ export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
public ngOnInit() {
this.$element = jQuery(this.elementRef.nativeElement);
const change = this.wpEditing.changeFor(this.workPackage);
const change = this.halEditing.changeFor<WorkPackageResource, WorkPackageChangeset>(this.workPackage);
this.resourceContextChange.next(this.contextFrom(change));
this.refresh(change);
@ -167,14 +168,14 @@ export class WorkPackageSingleViewComponent implements OnInit, OnDestroy {
.pipe(
takeUntil(componentDestroyed(this)),
distinctUntilChanged<ResourceContextChange>((a, b) => _.isEqual(a, b)),
map(() => this.wpEditing.changeFor(this.workPackage))
map(() => this.halEditing.changeFor(this.workPackage))
)
.subscribe((change:WorkPackageChangeset) => this.refresh(change));
// Update the resource context on every update to the temporary resource.
// This allows detecting a changed type value in a new work package.
this.wpEditing
.state(this.workPackage.id!)
this.halEditing
.typedState<WorkPackageResource, WorkPackageChangeset>(this.workPackage)
.values$()
.pipe(
takeUntil(componentDestroyed(this))

@ -3,9 +3,9 @@
[ngClass]="{'-can-have-columns' : enableTwoColumnLayout }">
<div class="wp-new--subject-wrapper"
*ngIf="workPackage.isNew">
<wp-edit-field [workPackageId]="workPackage.id"
<editable-attribute-field [resource]="workPackage"
[wrapperClasses]="'-no-label'"
[fieldName]="'subject'"></wp-edit-field>
[fieldName]="'subject'"></editable-attribute-field>
</div>
<div class="wp-info-wrapper">
@ -51,8 +51,8 @@
[attributeScope]="'WorkPackage'"></attribute-help-text>
</div>
<div class="attributes-key-value--value-container">
<wp-edit-field [workPackageId]="workPackage.id"
[fieldName]="descriptor.name"></wp-edit-field>
<editable-attribute-field [resource]="workPackage"
[fieldName]="descriptor.name"></editable-attribute-field>
</div>
</div>
</div>
@ -83,12 +83,12 @@
</div>
</div>
<div class="single-attribute work-packages--details--description">
<wp-edit-field [fieldName]="'description'"
[workPackageId]="workPackage.id"
<editable-attribute-field [fieldName]="'description'"
[resource]="workPackage"
[isDropTarget]="true"
[wrapperClasses]="'-no-label'"
[displayPlaceholder]="text.description.placeholder">
</wp-edit-field>
</editable-attribute-field>
</div>
</div>

@ -3,15 +3,15 @@
[ngClass]="'__overflowing_' + uniqueElementIdentifier"
[attr.data-overflowing-identifier]="'.__overflowing_' + uniqueElementIdentifier">
<div class="work-packages--type-selector work-packages--subject-element">
<wp-edit-field [workPackageId]="workPackage.id"
<editable-attribute-field [resource]="workPackage"
[wrapperClasses]="'work-packages--type-selector work-packages--subject-element -no-label'"
[fieldName]="'type'">
</wp-edit-field>
</editable-attribute-field>
</div>
<div class="work-packages--details--subject work-packages--subject-element">
<wp-edit-field [workPackageId]="workPackage.id"
<editable-attribute-field [resource]="workPackage"
[wrapperClasses]="'work-packages--details--subject work-packages--subject-element -no-label'"
[fieldName]="'subject'">
</wp-edit-field>
</editable-attribute-field>
</div>
</div>

@ -1,17 +1,16 @@
<div *ngIf="workPackage"
class="wp-new-top-row">
<div class="work-packages--status-selector wp-new-top-row--element">
<wp-edit-field [workPackageId]="workPackage.id"
<editable-attribute-field [resource]="workPackage"
[displayFieldOptions]="{ colorize: false }"
[wrapperClasses]="'wp-new-top-row--status -no-label'"
[fieldName]="'status'">
</wp-edit-field>
</editable-attribute-field>
</div>
<div class="work-packages--type-selector wp-new-top-row--element">
<wp-edit-field [workPackageId]="workPackage.id"
[displayFieldOptions]="{ colorize: false }"
<editable-attribute-field [resource]="workPackage"
[wrapperClasses]="'wp-new-top-row--type -no-label'"
[fieldName]="'type'">
</wp-edit-field>
</editable-attribute-field>
</div>
</div>

@ -32,8 +32,9 @@ import {NotificationsService} from 'core-app/modules/common/notifications/notifi
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {input, InputState} from 'reactivestates';
import {WorkPackageNotificationService} from './../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {Subject} from "rxjs";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Injectable()
export class CommentService {
@ -44,7 +45,7 @@ export class CommentService {
constructor(
readonly I18n:I18nService,
private wpNotificationsService:WorkPackageNotificationService,
private workPackageNotificationService:WorkPackageNotificationService,
private NotificationsService:NotificationsService) {
}
@ -78,7 +79,7 @@ export class CommentService {
}
private errorAndReject(error:HalResource, workPackage?:WorkPackageResource) {
this.wpNotificationsService.handleRawError(error, workPackage);
this.workPackageNotificationService.handleRawError(error, workPackage);
// returning a reject will enable to correctly work with subsequent then/catch handlers.
return Promise.reject(error);

@ -206,6 +206,10 @@ export class UserActivityComponent extends WorkPackageCommentFieldHandler implem
return this.focused;
}
setErrors(newErrors:string[]):void {
// interface
}
public quotedText(rawComment:string) {
let quoted = rawComment.split('\n')
.map(function(line:string) {

@ -27,7 +27,8 @@
// ++
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageEditingService} from 'core-components/wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {ChangeDetectorRef, Component, Inject, Input, OnDestroy, OnInit} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {Highlighting} from "core-components/wp-fast-table/builders/highlighting/highlighting.functions";
@ -54,12 +55,12 @@ export class WorkPackageStatusButtonComponent implements OnInit, OnDestroy {
constructor(readonly I18n:I18nService,
readonly cdRef:ChangeDetectorRef,
readonly wpCacheService:WorkPackageCacheService,
readonly wpEditing:WorkPackageEditingService) {
readonly halEditing:HalResourceEditingService) {
}
ngOnInit() {
this.wpEditing
.temporaryEditResource(this.workPackage.id!)
this.halEditing
.temporaryEditResource(this.workPackage)
.values$()
.pipe(
untilComponentDestroyed(this)
@ -97,7 +98,7 @@ export class WorkPackageStatusButtonComponent implements OnInit, OnDestroy {
}
public get status():HalResource|undefined {
if (!this.wpEditing) {
if (!this.halEditing) {
return;
}
@ -115,6 +116,6 @@ export class WorkPackageStatusButtonComponent implements OnInit, OnDestroy {
}
private get changeset() {
return this.wpEditing.changeFor(this.workPackage);
return this.halEditing.changeFor(this.workPackage);
}
}

@ -3,7 +3,7 @@ import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-r
import {WorkPackageViewOrderService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-order.service";
import {States} from "core-components/states.service";
import {WorkPackageCreateService} from "core-components/wp-new/wp-create.service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {CurrentProjectService} from "core-components/projects/current-project.service";
import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/wp-inline-create.service";
import {DragAndDropService} from "core-app/modules/common/drag-and-drop/drag-and-drop.service";
@ -11,6 +11,7 @@ import {DragAndDropHelpers} from "core-app/modules/common/drag-and-drop/drag-and
import {WorkPackageCardViewComponent} from "core-components/wp-card-view/wp-card-view.component";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {WorkPackageCacheService} from "core-components/work-packages/work-package-cache.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Injectable()
export class WorkPackageCardDragAndDropService {
@ -29,7 +30,7 @@ export class WorkPackageCardDragAndDropService {
readonly injector:Injector,
readonly reorderService:WorkPackageViewOrderService,
readonly wpCreate:WorkPackageCreateService,
readonly wpNotifications:WorkPackageNotificationService,
readonly notificationService:WorkPackageNotificationService,
readonly wpCacheService:WorkPackageCacheService,
readonly currentProject:CurrentProjectService,
readonly wpInlineCreate:WorkPackageInlineCreateService) {
@ -168,7 +169,7 @@ export class WorkPackageCardDragAndDropService {
this.updateOrder(newOrder);
return true;
} catch (e) {
this.wpNotifications.handleRawError(e, workPackage);
this.notificationService.handleRawError(e, workPackage);
}
return false;

@ -59,9 +59,6 @@
left: 0
border-radius: 2px 0 0 2px
wp-edit-field
width: initial
.wp-inline-create-button
font-size: 0.9rem
padding-top: 1rem

@ -36,21 +36,21 @@
</a>
</div>
<wp-edit-field-group [workPackage]="wp"
<edit-form [resource]="wp"
[inEditMode]="wp.isNew"
*ngIf="wp.isNew">
<div class="wp-card--content -new">
<wp-edit-field [workPackageId]="wp.id"
<editable-attribute-field [resource]="wp"
[wrapperClasses]="'work-packages--type-selector'"
[fieldName]="'type'"
class="wp-card--type">
</wp-edit-field>
<wp-edit-field [workPackageId]="wp.id"
</editable-attribute-field>
<editable-attribute-field [resource]="wp"
fieldName="subject"
class="wp-card--subject -bold">
</wp-edit-field>
</editable-attribute-field>
</div>
</wp-edit-field-group>
</edit-form>
<img *ngIf="this.bcfSnapshotPath(wp)" [src]="this.bcfSnapshotPath(wp)" class="wp-card--cover-image">

@ -21,7 +21,7 @@ import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/wp-inline-create.service";
import {WorkPackageCreateService} from "core-components/wp-new/wp-create.service";
import {AngularTrackingHelpers} from "core-components/angular/tracking-functions";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {Highlighting} from "core-components/wp-fast-table/builders/highlighting/highlighting.functions";
import {CardHighlightingMode} from "core-components/wp-fast-table/builders/highlighting/highlighting-mode.const";
import {AuthorisationService} from "core-app/modules/common/model-auth/model-auth.service";
@ -36,6 +36,7 @@ import {CardViewHandlerRegistry} from "core-components/wp-card-view/event-handle
import {WorkPackageCardViewService} from "core-components/wp-card-view/services/wp-card-view.service";
import {WorkPackageCardDragAndDropService} from "core-components/wp-card-view/services/wp-card-drag-and-drop.service";
import {checkedClassName, uiStateLinkClass} from "core-components/wp-fast-table/builders/ui-state-link-builder";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
export type CardViewOrientation = 'horizontal'|'vertical';
@ -99,7 +100,7 @@ export class WorkPackageCardViewComponent implements OnInit, AfterViewInit {
readonly I18n:I18nService,
readonly wpCreate:WorkPackageCreateService,
readonly wpInlineCreate:WorkPackageInlineCreateService,
readonly wpNotifications:WorkPackageNotificationService,
readonly notificationService:WorkPackageNotificationService,
readonly authorisationService:AuthorisationService,
readonly causedUpdates:CausedUpdatesService,
readonly cdRef:ChangeDetectorRef,

@ -31,9 +31,11 @@ import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-r
import {WorkPackageCreateController} from 'core-components/wp-new/wp-create.controller';
import {WorkPackageRelationsService} from "core-components/wp-relations/wp-relations.service";
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {ChangeDetectionStrategy} from "@angular/core";
import {WorkPackageCreateService} from "core-components/wp-new/wp-create.service";
export class WorkPackageCopyController extends WorkPackageCreateController {
private __initialized_at:Number;
@ -43,7 +45,8 @@ export class WorkPackageCopyController extends WorkPackageCreateController {
public copying = true;
private wpRelations:WorkPackageRelationsService = this.injector.get(WorkPackageRelationsService);
protected wpEditing:WorkPackageEditingService = this.injector.get(WorkPackageEditingService);
protected halEditing:HalResourceEditingService = this.injector.get(HalResourceEditingService);
protected wpCreate:WorkPackageCreateService = this.injector.get(WorkPackageCreateService);
ngOnInit() {
super.ngOnInit();
@ -78,15 +81,15 @@ export class WorkPackageCopyController extends WorkPackageCreateController {
}
private createCopyFrom(wp:WorkPackageResource) {
let sourceChangeset = this.wpEditing.changeFor(wp);
let sourceChangeset = this.halEditing.changeFor(wp) as WorkPackageChangeset;
return this.wpCreate
.copyWorkPackage(sourceChangeset)
.then((copyChangeset) => {
.then((copyChangeset:WorkPackageChangeset) => {
this.__initialized_at = copyChangeset.pristineResource.__initialized_at;
this.wpCacheService.updateWorkPackage(copyChangeset.pristineResource);
this.wpEditing.updateValue('new', copyChangeset);
this.halEditing.updateValue('new', copyChangeset);
return copyChangeset;
});

@ -30,13 +30,15 @@
import {Component, HostListener, Input, Inject} from '@angular/core';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from 'core-components/wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
import {CustomActionResource} from 'core-app/modules/hal/resources/custom-action-resource';
import {WorkPackagesActivityService} from 'core-components/wp-single-view-tabs/activity-panel/wp-activity.service';
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {SchemaCacheService} from "core-components/schemas/schema-cache.service";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
selector: 'wp-custom-action',
@ -51,9 +53,9 @@ export class WpCustomActionComponent {
private wpCacheService:WorkPackageCacheService,
private wpSchemaCacheService:SchemaCacheService,
private wpActivity:WorkPackagesActivityService,
private wpNotificationsService:WorkPackageNotificationService,
private wpEditing:WorkPackageEditingService,
private wpEvents:WorkPackageEventsService) {
private notificationService:WorkPackageNotificationService,
private halEditing:HalResourceEditingService,
private halEvents:HalEventsService) {
}
private fetchAction() {
@ -77,18 +79,18 @@ export class WpCustomActionComponent {
this.halResourceService.post<WorkPackageResource>(this.action.href + '/execute', payload)
.toPromise()
.then((savedWp:WorkPackageResource) => {
this.wpNotificationsService.showSave(savedWp, false);
this.notificationService.showSave(savedWp, false);
this.workPackage = savedWp;
this.wpActivity.clear(this.workPackage.id!);
// Loading the schema might be necessary in cases where the button switches
// project or type.
this.wpSchemaCacheService.ensureLoaded(savedWp).then(() => {
this.wpCacheService.updateWorkPackage(savedWp, true);
this.wpEditing.stopEditing(savedWp.id!);
this.wpEvents.push({ type: "updated", id: savedWp.id! });
this.halEditing.stopEditing(savedWp);
this.halEvents.push(savedWp, { eventType: "updated" });
});
}).catch((errorResource:any) => {
this.wpNotificationsService.handleRawError(errorResource, this.workPackage);
this.notificationService.handleRawError(errorResource, this.workPackage);
});
}

@ -25,7 +25,8 @@
//
// See doc/COPYRIGHT.rdoc for more details.
//++
import {WorkPackageEditingService} from '../wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {Component, Inject, Input} from '@angular/core';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
@ -42,5 +43,5 @@ export class WorkPackageSplitViewToolbarComponent {
}
constructor(readonly I18n:I18nService,
readonly wpEditing:WorkPackageEditingService) {}
readonly halEditing:HalResourceEditingService) {}
}

@ -1,24 +1,23 @@
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {Injector} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {IFieldSchema} from "core-app/modules/fields/field.base";
import {DisplayFieldContext, DisplayFieldService} from "core-app/modules/fields/display/display-field.service";
import {DisplayField} from "core-app/modules/fields/display/display-field.module";
import {MultipleLinesStringObjectsDisplayField} from "core-app/modules/fields/display/field-types/wp-display-multiple-lines-string-objects-field.module";
import {ProgressTextDisplayField} from "core-app/modules/fields/display/field-types/wp-display-progress-text-field.module";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {MultipleLinesUserFieldModule} from "core-app/modules/fields/display/field-types/wp-display-multiple-lines-user-field.module";
import {MultipleLinesStringObjectsDisplayField} from "core-app/modules/fields/display/field-types/multiple-lines-string-objects-display-field.module";
import {ProgressTextDisplayField} from "core-app/modules/fields/display/field-types/progress-text-display-field.module";
import {MultipleLinesUserFieldModule} from "core-app/modules/fields/display/field-types/multiple-lines-user-display-field.module";
import {ResourceChangeset} from "core-app/modules/fields/changeset/resource-changeset";
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
export const editableClassName = '-editable';
export const requiredClassName = '-required';
export const readOnlyClassName = '-read-only';
export const placeholderClassName = '-placeholder';
export const cellClassName = 'wp-table--cell-span';
export const displayClassName = 'wp-edit-field--display-field';
export const editFieldContainerClass = 'wp-edit-field--container';
export const displayClassName = 'inline-edit--display-field';
export const editFieldContainerClass = 'inline-edit--container';
export const cellEmptyPlaceholder = '-';
export class DisplayFieldRenderer {
export class DisplayFieldRenderer<T extends HalResource = HalResource> {
readonly displayFieldService:DisplayFieldService = this.injector.get(DisplayFieldService);
readonly I18n:I18nService = this.injector.get(I18nService);
@ -27,70 +26,70 @@ export class DisplayFieldRenderer {
private fieldCache:{ [key:string]:DisplayField } = {};
constructor(public readonly injector:Injector,
public readonly container:'table' | 'single-view' | 'timeline',
public readonly options:{ [key:string]: any } = {}) {
public readonly container:'table'|'single-view'|'timeline',
public readonly options:{ [key:string]:any } = {}) {
}
public render(workPackage:WorkPackageResource,
public render(resource:T,
name:string,
change:WorkPackageChangeset|null,
change:ResourceChangeset<T>|null,
placeholder = cellEmptyPlaceholder):HTMLSpanElement {
const [field, span] = this.renderFieldValue(workPackage, name, change, placeholder);
const [field, span] = this.renderFieldValue(resource, name, change, placeholder);
if (field === null) {
return span;
}
this.setSpanAttributes(span, field, name, workPackage);
this.setSpanAttributes(span, field, name, resource);
return span;
}
public renderFieldValue(workPackage:WorkPackageResource,
public renderFieldValue(resource:T,
name:string,
change:WorkPackageChangeset|null,
change:ResourceChangeset<T>|null,
placeholder = cellEmptyPlaceholder):[DisplayField|null, HTMLSpanElement] {
const span = document.createElement('span');
const schemaName = workPackage.getSchemaName(name);
const fieldSchema = workPackage.schema[schemaName];
const schemaName = this.getSchemaName(resource, change, name);
const fieldSchema = resource.schema[schemaName];
// If the work package does not have that field, return an empty
// If the resource does not have that field, return an empty
// span (e.g., for the table).
if (!fieldSchema) {
return [null, span];
}
const field = this.getField(workPackage, fieldSchema, schemaName, change);
const field = this.getField(resource, fieldSchema, schemaName, change);
field.render(span, this.getText(field, placeholder));
const title = field.title;
if (title) {
span.setAttribute('title', title);
}
span.setAttribute('aria-label', this.getAriaLabel(field, workPackage));
span.setAttribute('aria-label', this.getAriaLabel(field, resource));
return [field, span];
}
public getField(workPackage:WorkPackageResource,
public getField(resource:T,
fieldSchema:IFieldSchema,
name:string,
change:WorkPackageChangeset|null):DisplayField {
change:ResourceChangeset<T>|null):DisplayField {
let field = this.fieldCache[name];
if (!field) {
field = this.fieldCache[name] = this.getFieldForCurrentContext(workPackage, name, fieldSchema);
field = this.fieldCache[name] = this.getFieldForCurrentContext(resource, name, fieldSchema);
}
field.apply(workPackage, fieldSchema);
field.apply(resource, fieldSchema);
field.activeChange = change;
return field;
}
private getFieldForCurrentContext(workPackage:WorkPackageResource, name:string, fieldSchema:IFieldSchema):DisplayField {
const context:DisplayFieldContext = { container: this.container, injector: this.injector, options: this.options };
private getFieldForCurrentContext(resource:T, name:string, fieldSchema:IFieldSchema):DisplayField {
const context:DisplayFieldContext = {container: this.container, injector: this.injector, options: this.options};
// We handle multi value fields differently in the single view context
const isCustomMultiLinesField = ['[]CustomOption'].indexOf(fieldSchema.type) >= 0;
@ -107,7 +106,7 @@ export class DisplayFieldRenderer {
return new ProgressTextDisplayField(name, context);
}
return this.displayFieldService.getField(workPackage, name, fieldSchema, context);
return this.displayFieldService.getField(resource, name, fieldSchema, context);
}
private getText(field:DisplayField, placeholder:string):string {
@ -118,8 +117,8 @@ export class DisplayFieldRenderer {
}
}
private setSpanAttributes(span:HTMLElement, field:DisplayField, name:string, workPackage:WorkPackageResource):void {
span.classList.add(cellClassName, displayClassName, 'inplace-edit', 'wp-edit-field', name);
private setSpanAttributes(span:HTMLElement, field:DisplayField, name:string, resource:T):void {
span.classList.add(displayClassName, name);
span.dataset['fieldName'] = name;
// Make span tabbable unless it's an id field
@ -133,7 +132,7 @@ export class DisplayFieldRenderer {
span.classList.add(placeholderClassName);
}
if (field.writable && workPackage.isAttributeEditable(field.name)) {
if (field.writable) {
span.classList.add(editableClassName);
span.setAttribute('role', 'button');
} else {
@ -141,7 +140,7 @@ export class DisplayFieldRenderer {
}
}
private getAriaLabel(field:DisplayField, workPackage:WorkPackageResource):string {
private getAriaLabel(field:DisplayField, resource:T):string {
let titleContent;
let labelContent = this.getLabelContent(field);
@ -157,8 +156,8 @@ export class DisplayFieldRenderer {
titleContent = labelContent;
}
if (field.writable && workPackage.isAttributeEditable(field.name)) {
return this.I18n.t('js.inplace.button_edit', { attribute: `${field.displayName} ${titleContent}` });
if (field.writable && resource.isAttributeEditable(field.name)) {
return this.I18n.t('js.inplace.button_edit', {attribute: `${field.displayName} ${titleContent}`});
} else {
return `${field.displayName} ${titleContent}`;
}
@ -171,4 +170,25 @@ export class DisplayFieldRenderer {
return field.valueString;
}
}
/**
* Get the schema name from either the changeset, the resource (if available) or
* return the attribute itself.
*
* @param resource
* @param change
* @param name
*/
private getSchemaName(resource:T, change:ResourceChangeset<T>|null, name:string) {
if (change) {
return change.getSchemaName(name);
}
if (!!resource.getSchemaName) {
return resource.getSchemaName(name);
}
return name;
}
}

@ -1,106 +0,0 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {StateService} from '@uirouter/core';
import {WorkPackageEditFieldGroupComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field-group.directive';
import {WorkPackageEditFieldComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field.component';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {States} from '../states.service';
import {WorkPackageNotificationService} from '../wp-edit/wp-notification.service';
import {Injector} from '@angular/core';
import {WorkPackageEditContext} from 'core-components/wp-edit-form/work-package-edit-context';
import {WorkPackageEditForm} from 'core-components/wp-edit-form/work-package-edit-form';
import {WorkPackageEditFieldHandler} from 'core-components/wp-edit-form/work-package-edit-field-handler';
import {FocusHelperService} from 'core-app/modules/common/focus/focus-helper';
import {WorkPackageEditingPortalService} from "core-app/modules/fields/edit/editing-portal/wp-editing-portal-service";
import {IFieldSchema} from "core-app/modules/fields/field.base";
import {WorkPackageViewSelectionService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-selection.service";
export class SingleViewEditContext implements WorkPackageEditContext {
// Injections
public states:States = this.injector.get(States);
public FocusHelper:FocusHelperService = this.injector.get(FocusHelperService);
public $state:StateService = this.injector.get(StateService);
public wpNotificationsService:WorkPackageNotificationService = this.injector.get(WorkPackageNotificationService);
public wpEditingPortalService:WorkPackageEditingPortalService = this.injector.get(WorkPackageEditingPortalService);
protected wpTableSelection:WorkPackageViewSelectionService = this.injector.get(WorkPackageViewSelectionService);
// other fields
public successState:string;
constructor(readonly injector:Injector,
readonly fieldGroup:WorkPackageEditFieldGroupComponent) {
}
public async activateField(form:WorkPackageEditForm, schema:IFieldSchema, fieldName:string, errors:string[]):Promise<WorkPackageEditFieldHandler> {
return this.fieldCtrl(fieldName).then((ctrl) => {
ctrl.setActive(true);
const container = ctrl.editContainer.nativeElement;
return this.wpEditingPortalService.create(
container,
this.injector,
form,
schema,
fieldName,
errors
);
});
}
public async reset(workPackage:WorkPackageResource, fieldName:string, focus:boolean = false) {
const ctrl = await this.fieldCtrl(fieldName);
ctrl.reset();
ctrl.deactivate(focus);
}
public onSaved(isInitial:boolean, savedWorkPackage:WorkPackageResource) {
this.fieldGroup.stopEditingAndLeave(savedWorkPackage, isInitial);
}
public requireVisible(fieldName:string):Promise<void> {
return new Promise<void>((resolve,) => {
const interval = setInterval(() => {
const field = this.fieldGroup.fields[fieldName];
if (field !== undefined) {
clearInterval(interval);
resolve();
}
}, 50);
});
}
public firstField(names:string[]) {
return 'subject';
}
private fieldCtrl(name:string):Promise<WorkPackageEditFieldComponent> {
return this.fieldGroup.waitForField(name);
}
}

@ -27,38 +27,57 @@
// ++
import {Injector} from '@angular/core';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {States} from '../states.service';
import {CellBuilder, editCellContainer, tdClassName} from '../wp-fast-table/builders/cell-builder';
import {WorkPackageEditContext} from './work-package-edit-context';
import {WorkPackageEditFieldHandler} from './work-package-edit-field-handler';
import {WorkPackageEditForm} from './work-package-edit-form';
import {FocusHelperService} from 'core-app/modules/common/focus/focus-helper';
import {WorkPackageTable} from 'core-components/wp-fast-table/wp-fast-table';
import {WorkPackageEditingPortalService} from "core-app/modules/fields/edit/editing-portal/wp-editing-portal-service";
import {ErrorResource} from 'core-app/modules/hal/resources/error-resource';
import {Observable, Subscription} from 'rxjs';
import {States} from 'core-components/states.service';
import {IFieldSchema} from "core-app/modules/fields/field.base";
import {editModeClassName} from "core-app/modules/fields/edit/edit-field.component";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {EditFieldHandler} from "core-app/modules/fields/edit/editing-portal/edit-field-handler";
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
import {ResourceChangeset} from "core-app/modules/fields/changeset/resource-changeset";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageViewColumnsService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-columns.service";
import {FocusHelperService} from "core-app/modules/common/focus/focus-helper";
import {EditingPortalService} from "core-app/modules/fields/edit/editing-portal/editing-portal-service";
import {CellBuilder, editCellContainer, tdClassName} from "core-components/wp-fast-table/builders/cell-builder";
import {WorkPackageTable} from "core-components/wp-fast-table/wp-fast-table";
import {EditForm} from "core-app/modules/fields/edit/edit-form/edit-form";
import {editModeClassName} from "core-app/modules/fields/edit/edit-field.component";
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
import {WorkPackageCacheService} from "core-components/work-packages/work-package-cache.service";
export class TableRowEditContext implements WorkPackageEditContext {
export const activeFieldContainerClassName = 'inline-edit--active-field';
export const activeFieldClassName = 'inline-edit--field';
export class TableEditForm extends EditForm<WorkPackageResource> {
// Injections
public wpTableColumns:WorkPackageViewColumnsService = this.injector.get(WorkPackageViewColumnsService);
public wpCacheService:WorkPackageCacheService = this.injector.get(WorkPackageCacheService);
public states:States = this.injector.get(States);
public FocusHelper:FocusHelperService = this.injector.get(FocusHelperService);
public wpEditingPortalService:WorkPackageEditingPortalService = this.injector.get(WorkPackageEditingPortalService);
// other fields
public successState:string;
public editingPortalService:EditingPortalService = this.injector.get(EditingPortalService);
// Use cell builder to reset edit fields
private cellBuilder = new CellBuilder(this.injector);
constructor(readonly table:WorkPackageTable,
readonly injector:Injector,
// Subscription
private resourceSubscription:Subscription = this.wpCacheService
.requireAndStream(this.workPackageId)
.subscribe((wp) => this.resource = wp);
constructor(protected readonly injector:Injector,
protected readonly table:WorkPackageTable,
public workPackageId:string,
public classIdentifier:string) {
// injectorBridge(this);
super(injector);
}
destroy() {
this.resourceSubscription.unsubscribe();
super.destroy();
}
public findContainer(fieldName:string):JQuery {
@ -69,39 +88,39 @@ export class TableRowEditContext implements WorkPackageEditContext {
return this.rowContainer.find(`.${tdClassName}.${fieldName}`).first();
}
public activateField(form:WorkPackageEditForm, schema:IFieldSchema, fieldName:string, errors:string[]):Promise<WorkPackageEditFieldHandler> {
public activateField(form:EditForm, schema:IFieldSchema, fieldName:string, errors:string[]):Promise<EditFieldHandler> {
return this.waitForContainer(fieldName)
.then((cell) => {
// Forcibly set the width since the edit field may otherwise
// be given more width. Thereby preserve a minimum width of 150.
// To avoid flickering content, the padding is removed, too.
const td = this.findCell(fieldName);
td.addClass(editModeClassName);
var width = parseInt(td.css('width'));
width = width > 150 ? width - 10 : 150;
td.css('max-width', width + 'px');
td.css('width', width + 'px');
return this.wpEditingPortalService.create(
cell,
this.injector,
form,
schema,
fieldName,
errors
);
});
.then((cell) => {
// Forcibly set the width since the edit field may otherwise
// be given more width. Thereby preserve a minimum width of 150.
// To avoid flickering content, the padding is removed, too.
const td = this.findCell(fieldName);
td.addClass(editModeClassName);
let width = parseInt(td.css('width'));
width = width > 150 ? width - 10 : 150;
td.css('max-width', width + 'px');
td.css('width', width + 'px');
return this.editingPortalService.create(
cell,
this.injector,
form,
schema,
fieldName,
errors
);
});
}
public reset(workPackage:WorkPackageResource, fieldName:string, focus?:boolean) {
public reset(fieldName:string, focus?:boolean) {
const cell = this.findContainer(fieldName);
const td = this.findCell(fieldName);
if (cell.length) {
this.findCell(fieldName).css('width', '');
this.findCell(fieldName).css('max-width', '');
this.cellBuilder.refresh(cell[0], workPackage, fieldName);
this.cellBuilder.refresh(cell[0], this.resource, fieldName);
td.removeClass(editModeClassName);
if (focus) {
@ -115,11 +134,12 @@ export class TableRowEditContext implements WorkPackageEditContext {
return this.waitForContainer(fieldName);
}
public firstField(names:string[]) {
return 'subject';
}
public onSaved(isInitial:boolean, savedWorkPackage:WorkPackageResource) {
protected focusOnFirstError():void {
// Focus the first field that is erroneous
jQuery(this.table.tableAndTimelineContainer)
.find(`.${activeFieldContainerClassName}.-error .${activeFieldClassName}`)
.first()
.trigger('focus');
}
// Ensure the given field is visible.
@ -140,4 +160,5 @@ export class TableRowEditContext implements WorkPackageEditContext {
private get rowContainer() {
return jQuery(this.table.tableAndTimelineContainer).find(`.${this.classIdentifier}-table`);
}
}

@ -1,59 +0,0 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2017 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageEditForm} from './work-package-edit-form';
import {WorkPackageEditFieldHandler} from './work-package-edit-field-handler';
import {IFieldSchema} from "core-app/modules/fields/field.base";
export interface WorkPackageEditContext {
/**
* Activate the field, returning the element and associated field handler
*/
activateField(form:WorkPackageEditForm, schema:IFieldSchema, fieldName:string, errors:string[]):Promise<WorkPackageEditFieldHandler>;
/**
* Show this required field. E.g., add the necessary column
*/
requireVisible(fieldName:string):Promise<void>;
/**
* Reset the field and re-render the current WPs value.
*/
reset(workPackage:WorkPackageResource, fieldName:string, focus?:boolean):void;
/**
* Return the first relevant field from the given list of attributes.
*/
firstField(names:string[]):string;
/**
* Optional callback when the form is being saved
*/
onSaved(isInitial:boolean, savedWorkPackage:WorkPackageResource):void;
}

@ -33,10 +33,11 @@ import {Injector} from "@angular/core";
import {WorkPackageCacheService} from "core-components/work-packages/work-package-cache.service";
import {SchemaCacheService} from "core-components/schemas/schema-cache.service";
import {WorkPackageFilterValues} from "core-components/wp-edit-form/work-package-filter-values";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackagesActivityService} from "core-components/wp-single-view-tabs/activity-panel/wp-activity.service";
import {WorkPackageCreateService} from "core-components/wp-new/wp-create.service";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
import {TypeResource} from "core-app/modules/hal/resources/type-resource";
import {HttpClientModule} from "@angular/common/http";
@ -51,9 +52,10 @@ import {LoadingIndicatorService} from "core-app/modules/common/loading-indicator
import {OpenProjectFileUploadService} from "core-components/api/op-file-upload/op-file-upload.service";
import {HookService} from "core-app/modules/plugins/hook-service";
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {TimezoneService} from "core-components/datetime/timezone.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
describe('WorkPackageFilterValues', () => {
let resource:WorkPackageResource;
@ -76,7 +78,7 @@ describe('WorkPackageFilterValues', () => {
I18nService,
States,
IsolatedQuerySpace,
WorkPackageEventsService,
HalEventsService,
TimezoneService,
PathHelperService,
ConfigurationService,
@ -87,11 +89,12 @@ describe('WorkPackageFilterValues', () => {
WorkPackageDmService,
HalResourceService,
NotificationsService,
WorkPackageNotificationService,
HalResourceNotificationService,
SchemaCacheService,
WorkPackageNotificationService,
WorkPackageCacheService,
WorkPackageCreateService,
WorkPackageEditingService,
HalResourceEditingService,
WorkPackagesActivityService,
]
}).compileComponents();

@ -1,218 +0,0 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {Component, Injector, Input, OnDestroy, OnInit} from '@angular/core';
import {StateService, Transition, TransitionService} from '@uirouter/core';
import {ConfigurationService} from 'core-app/modules/common/config/configuration.service';
import {WorkPackageEditFieldComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field.component';
import {WorkPackageViewFocusService} from 'core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-focus.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {input} from 'reactivestates';
import {filter, map, take, takeUntil} from 'rxjs/operators';
import {States} from '../../states.service';
import {SingleViewEditContext} from '../../wp-edit-form/single-view-edit-context';
import {WorkPackageEditForm} from '../../wp-edit-form/work-package-edit-form';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageNotificationService} from '../wp-notification.service';
import {WorkPackageCreateService} from './../../wp-new/wp-create.service';
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {WorkPackageViewSelectionService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-selection.service";
@Component({
selector: 'wp-edit-field-group,[wp-edit-field-group]',
template: '<ng-content></ng-content>'
})
export class WorkPackageEditFieldGroupComponent implements OnInit, OnDestroy {
@Input('workPackage') workPackage:WorkPackageResource;
@Input('successState') successState?:string;
@Input('inEditMode') initializeEditMode:boolean = false;
public form:WorkPackageEditForm;
public fields:{ [attribute:string]:WorkPackageEditFieldComponent } = {};
private registeredFields = input<string[]>();
private unregisterListener:Function;
constructor(protected states:States,
protected injector:Injector,
protected wpCreate:WorkPackageCreateService,
protected wpEditing:WorkPackageEditingService,
protected wpNotificationsService:WorkPackageNotificationService,
protected wpTableSelection:WorkPackageViewSelectionService,
protected wpTableFocus:WorkPackageViewFocusService,
protected $transitions:TransitionService,
protected ConfigurationService:ConfigurationService,
readonly $state:StateService,
readonly I18n:I18nService) {
const confirmText = I18n.t('js.work_packages.confirm_edit_cancel');
const requiresConfirmation = ConfigurationService.warnOnLeavingUnsaved();
this.unregisterListener = $transitions.onBefore({}, (transition:Transition) => {
if (!this.editing) {
return undefined;
}
// Show confirmation message when transitioning to a new state
// that's not withing the edit mode.
const toState = transition.to();
const fromState = transition.from();
const fromParams = transition.params('from');
const toParams = transition.params('to');
if (!this.allowedStateChange(toState, toParams, fromState, fromParams)) {
if (requiresConfirmation && !window.confirm(confirmText)) {
return false;
}
this.stop();
}
return true;
});
}
ngOnDestroy() {
this.unregisterListener();
this.form.destroy();
}
ngOnInit() {
const context = new SingleViewEditContext(this.injector, this);
this.form = WorkPackageEditForm.createInContext(this.injector, context, this.workPackage, this.initializeEditMode);
if (this.initializeEditMode) {
this.start();
}
// Stop editing whenever a work package was saved
if (this.initializeEditMode && this.workPackage.isNew) {
this.wpCreate.onNewWorkPackage()
.pipe(
takeUntil(componentDestroyed(this))
)
.subscribe((wp:WorkPackageResource) => {
this.form.editMode = false;
this.stopEditingAndLeave(wp, true);
});
}
}
public get editing():boolean {
return this.editMode || this.form.hasActiveFields();
}
public get editMode() {
return this.form.editMode;
}
public register(field:WorkPackageEditFieldComponent) {
this.fields[field.fieldName] = field;
this.registeredFields.putValue(_.keys(this.fields));
const shouldActivate =
(this.editMode && !this.skipField(field) || this.form.activeFields[field.fieldName]);
if (shouldActivate) {
field.activateOnForm(true);
}
}
public waitForField(name:string):Promise<WorkPackageEditFieldComponent> {
return this.registeredFields
.values$()
.pipe(
filter(keys => keys.indexOf(name) >= 0),
take(1),
map(() => this.fields[name])
)
.toPromise();
}
public start() {
_.each(this.fields, ctrl => this.form.activate(ctrl.fieldName));
}
public stop() {
this.form.editMode = false;
this.wpEditing.stopEditing(this.workPackage.id!);
this.form.destroy();
if (this.workPackage.isNew) {
this.wpCreate.cancelCreation();
}
}
public saveWorkPackage() {
const isInitial = this.workPackage.isNew;
return this.form
.submit()
.then((savedWorkPackage) => {
this.stopEditingAndLeave(savedWorkPackage, isInitial);
});
}
public stopEditingAndLeave(savedWorkPackage:WorkPackageResource, isInitial:boolean) {
this.stop();
if (this.successState) {
this.$state.go(this.successState, {workPackageId: savedWorkPackage.id})
.then(() => {
this.wpTableFocus.updateFocus(savedWorkPackage.id!);
this.wpNotificationsService.showSave(savedWorkPackage, isInitial);
});
}
}
private skipField(field:WorkPackageEditFieldComponent) {
const fieldName = field.fieldName;
const isSkipField = fieldName === 'status' || fieldName === 'type';
// Only skip status or type
if (!isSkipField) {
return false;
}
// Only skip if value present and not changed in changeset
const hasDefault = this.workPackage[fieldName];
const changed = this.form.change.changes[fieldName];
return hasDefault && !changed;
}
private allowedStateChange(toState:any, toParams:any, fromState:any, fromParams:any) {
// In new/copy mode, transitions to the same controller are allowed
if (fromState.name.match(/\.(new|copy)$/)) {
return toState.data && toState.data.allowMovingInEditMode;
}
// When editing an existing WP, transitions on the same WP id are allowed
return toParams.workPackageId !== undefined && toParams.workPackageId === fromParams.workPackageId;
}
}

@ -27,8 +27,8 @@
// ++
import {WorkPackageEditFieldGroupComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field-group.directive';
import {Component, ElementRef, Input, OnInit} from '@angular/core';
import {EditFormComponent} from "core-app/modules/fields/edit/edit-form/edit-form.component";
@Component({
selector: 'wp-replacement-label',
@ -38,7 +38,7 @@ export class WorkPackageReplacementLabelComponent implements OnInit {
@Input('fieldName') public fieldName:string;
private $element:JQuery;
constructor(protected wpEditFieldGroup:WorkPackageEditFieldGroupComponent,
constructor(protected wpeditForm:EditFormComponent,
protected elementRef:ElementRef) {
}
@ -53,7 +53,7 @@ export class WorkPackageReplacementLabelComponent implements OnInit {
return true;
}
const field = this.wpEditFieldGroup.fields[this.fieldName];
const field = this.wpeditForm.fields[this.fieldName];
field && field.handleUserActivate(null);
return false;

@ -7,7 +7,6 @@ import {Injector} from '@angular/core';
import {QueryColumn} from "core-components/wp-query/query-column";
export const tdClassName = 'wp-table--cell-td';
export const editCellContainer = 'wp-table--cell-container';
export const wpCellTdClassName = 'wp-table--cell-td';
export class CellBuilder {
@ -19,7 +18,7 @@ export class CellBuilder {
public build(workPackage:WorkPackageResource, column:QueryColumn) {
const td = document.createElement('td');
const attribute = column.id;
td.classList.add(tdClassName, wpCellTdClassName, attribute);
td.classList.add(tdClassName, attribute);
if (attribute === 'subject') {
td.classList.add('-max');

@ -1,5 +1,5 @@
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
import {wpCellTdClassName} from "core-components/wp-fast-table/builders/cell-builder";
import {tdClassName} from "core-components/wp-fast-table/builders/cell-builder";
import {Injector} from "@angular/core";
import {TableDragActionsRegistryService} from "core-components/wp-table/drag-and-drop/actions/table-drag-actions-registry.service";
import {TableDragActionService} from "core-components/wp-table/drag-and-drop/actions/table-drag-action.service";
@ -29,7 +29,7 @@ export class DragDropHandleBuilder {
return td;
}
td.classList.add(wpCellTdClassName, 'wp-table--sort-td', internalSortColumn.id, 'hide-when-print');
td.classList.add(tdClassName, 'wp-table--sort-td', internalSortColumn.id, 'hide-when-print');
// Wrap handle as span
let span = document.createElement('span');

@ -3,7 +3,8 @@ import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {timeOutput} from '../../../helpers/debug_output';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {States} from '../../states.service';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageTable} from '../wp-fast-table';
import {RelationRenderInfo, RelationsRenderPass} from './relations/relations-render-pass';
import {SingleRowBuilder} from './rows/single-row-builder';
@ -36,7 +37,7 @@ export interface RowRenderInfo {
export abstract class PrimaryRenderPass {
protected readonly wpEditing:WorkPackageEditingService = this.injector.get(WorkPackageEditingService);
protected readonly halEditing:HalResourceEditingService = this.injector.get(HalResourceEditingService);
protected readonly states:States = this.injector.get(States);
protected readonly I18n:I18nService = this.injector.get(I18nService);

@ -4,7 +4,7 @@ import {RelationResource} from 'core-app/modules/hal/resources/relation-resource
import {States} from '../../../states.service';
import {isRelationColumn, QueryColumn} from '../../../wp-query/query-column';
import {WorkPackageTable} from '../../wp-fast-table';
import {wpCellTdClassName} from '../cell-builder';
import {tdClassName} from '../cell-builder';
import {commonRowClassName, SingleRowBuilder, tableRowClassName} from '../rows/single-row-builder';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {RelationColumnType} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-relation-columns.service";
@ -120,7 +120,7 @@ export class RelationRowBuilder extends SingleRowBuilder {
protected emptyRelationCell(column:QueryColumn) {
const cell = document.createElement('td');
cell.classList.add(relationCellClassName, wpCellTdClassName, column.id);
cell.classList.add(relationCellClassName, tdClassName, column.id);
return cell;
}

@ -6,7 +6,7 @@ import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-r
import {isRelationColumn, QueryColumn} from '../../../wp-query/query-column';
import {WorkPackageViewColumnsService} from 'core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-columns.service';
import {WorkPackageTable} from '../../wp-fast-table';
import {CellBuilder, wpCellTdClassName} from '../cell-builder';
import {CellBuilder, tdClassName} from '../cell-builder';
import {RelationCellbuilder} from '../relation-cell-builder';
import {checkedClassName} from '../ui-state-link-builder';
import {TableActionRenderer} from 'core-components/wp-fast-table/builders/table-action-renderer';
@ -141,7 +141,7 @@ export class SingleRowBuilder {
*/
public refreshRow(workPackage:WorkPackageResource, jRow:JQuery):JQuery {
// Detach all current edit cells
const cells = jRow.find(`.${wpCellTdClassName}`).detach();
const cells = jRow.find(`.${tdClassName}`).detach();
// Remember the order of all new edit cells
const newCells:HTMLElement[] = [];
@ -175,7 +175,7 @@ export class SingleRowBuilder {
}
protected buildEmptyRow(workPackage:WorkPackageResource, row:HTMLTableRowElement):[HTMLTableRowElement, boolean] {
const change = this.workPackageTable.editing.change(workPackage.id!);
const change = this.workPackageTable.editing.change(workPackage);
let cells:{ [attribute:string]:JQuery } = {};
if (change && !change.isEmpty()) {
@ -183,7 +183,7 @@ export class SingleRowBuilder {
const oldRow = locateTableRowByIdentifier(this.classIdentifier(workPackage));
change.changedAttributes.forEach((attribute:string) => {
cells[attribute] = oldRow.find(`.${wpCellTdClassName}.${attribute}`);
cells[attribute] = oldRow.find(`.${tdClassName}.${attribute}`);
});
}

@ -1,5 +1,5 @@
import {Injector} from '@angular/core';
import {wpCellTdClassName} from './cell-builder';
import {tdClassName} from './cell-builder';
import {OpTableActionsService} from 'core-components/wp-table/table-actions/table-actions.service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {contextMenuSpanClassName, contextMenuTdClassName} from "core-components/wp-table/table-actions/table-action";
@ -16,7 +16,7 @@ export class TableActionRenderer {
public build(workPackage:WorkPackageResource):HTMLElement {
// Append details button
let td = document.createElement('td');
td.classList.add(wpCellTdClassName, contextMenuTdClassName, internalContextMenuColumn.id, 'hide-when-print');
td.classList.add(tdClassName, contextMenuTdClassName, internalContextMenuColumn.id, 'hide-when-print');
// Wrap any actions in a span
let span = document.createElement('span');

@ -1,8 +1,9 @@
import {Injector} from '@angular/core';
import {debugLog} from '../../../../helpers/debug_output';
import {States} from '../../../states.service';
import {cellClassName, editableClassName, readOnlyClassName} from '../../../wp-edit-form/display-field-renderer';
import {WorkPackageEditingService} from '../../../wp-edit-form/work-package-editing-service';
import {displayClassName, editableClassName, readOnlyClassName} from '../../../wp-edit-form/display-field-renderer';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {tableRowClassName} from '../../builders/rows/single-row-builder';
import {WorkPackageTable} from '../../wp-fast-table';
import {ClickOrEnterHandler} from '../click-or-enter-handler';
@ -13,7 +14,7 @@ export class EditCellHandler extends ClickOrEnterHandler implements TableEventHa
// Injections
public states:States = this.injector.get(States);
public wpEditing:WorkPackageEditingService = this.injector.get(WorkPackageEditingService);
public halEditing:HalResourceEditingService = this.injector.get(HalResourceEditingService);
// Keep a reference to all
@ -22,7 +23,7 @@ export class EditCellHandler extends ClickOrEnterHandler implements TableEventHa
}
public get SELECTOR() {
return `.${cellClassName}.${editableClassName}`;
return `.${displayClassName}.${editableClassName}`;
}
public eventScope(table:WorkPackageTable) {
@ -38,7 +39,7 @@ export class EditCellHandler extends ClickOrEnterHandler implements TableEventHa
evt.preventDefault();
// Locate the cell from event
let target = jQuery(evt.target).closest(`.${cellClassName}`);
let target = jQuery(evt.target).closest(`.${displayClassName}`);
// Get the target field name
let fieldName = target.data('fieldName');

@ -3,7 +3,7 @@ import {StateService} from '@uirouter/core';
import {WorkPackageViewFocusService} from 'core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-focus.service';
import {debugLog} from '../../../../helpers/debug_output';
import {States} from '../../../states.service';
import {tdClassName, wpCellTdClassName} from '../../builders/cell-builder';
import {tdClassName} from '../../builders/cell-builder';
import {tableRowClassName} from '../../builders/rows/single-row-builder';
import {WorkPackageTable} from '../../wp-fast-table';
import {TableEventHandler} from '../table-handler-registry';
@ -27,7 +27,7 @@ export class RowDoubleClickHandler implements TableEventHandler {
}
public get SELECTOR() {
return `.${wpCellTdClassName}`;
return `.${tdClassName}`;
}
public eventScope(table:WorkPackageTable) {

@ -3,7 +3,7 @@ import {WorkPackageTable} from '../../wp-fast-table';
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {take, takeUntil} from "rxjs/operators";
import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/wp-inline-create.service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageViewSortByService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-sort-by.service";
import {TableDragActionsRegistryService} from "core-components/wp-table/drag-and-drop/actions/table-drag-actions-registry.service";
import {TableDragActionService} from "core-components/wp-table/drag-and-drop/actions/table-drag-action.service";
@ -24,7 +24,7 @@ export class DragAndDropTransformer {
private readonly querySpace:IsolatedQuerySpace = this.injector.get(IsolatedQuerySpace);
private readonly dragService:DragAndDropService|null = this.injector.get(DragAndDropService, null);
private readonly inlineCreateService = this.injector.get(WorkPackageInlineCreateService);
private readonly wpNotifications = this.injector.get(WorkPackageNotificationService);
private readonly halNotification = this.injector.get(HalResourceNotificationService);
private readonly wpTableSortBy = this.injector.get(WorkPackageViewSortByService);
private readonly wpTableOrder = this.injector.get(WorkPackageViewOrderService);
private readonly browserDetector = this.injector.get(BrowserDetector);
@ -85,7 +85,7 @@ export class DragAndDropTransformer {
await this.wpListService.save(query);
}
} catch (e) {
this.wpNotifications.handleRawError(e);
this.halNotification.handleRawError(e);
// Restore element in from container
DragAndDropHelpers.reinsert(el, el.dataset.sourceIndex || -1, source);

@ -1,41 +1,42 @@
import {Injector} from '@angular/core';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {TableRowEditContext} from '../wp-edit-form/table-row-edit-context';
import {WorkPackageEditForm} from '../wp-edit-form/work-package-edit-form';
import {WorkPackageEditingService} from '../wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageTable} from 'core-components/wp-fast-table/wp-fast-table';
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {EditForm} from "core-app/modules/fields/edit/edit-form/edit-form";
import {TableEditForm} from "core-components/wp-edit-form/table-edit-form";
export class WorkPackageTableEditingContext {
public wpEditing:WorkPackageEditingService = this.injector.get(WorkPackageEditingService);
public halEditing:HalResourceEditingService = this.injector.get(HalResourceEditingService);
constructor(readonly table:WorkPackageTable,
readonly injector:Injector) {
}
public forms:{ [wpId:string]:WorkPackageEditForm } = {};
public forms:{ [wpId:string]:TableEditForm } = {};
public reset() {
_.each(this.forms, (form) => form.destroy());
this.forms = {};
}
public change(workPackageId:string):WorkPackageChangeset | undefined {
return this.wpEditing.state(workPackageId).value;
public change(workPackage:WorkPackageResource):WorkPackageChangeset|undefined {
return this.halEditing.typedState<WorkPackageResource, WorkPackageChangeset>(workPackage).value;
}
public stopEditing(workPackageId:string) {
this.wpEditing.stopEditing(workPackageId);
// TODO
public stopEditing(workPackage:WorkPackageResource) {
this.halEditing.stopEditing(workPackage);
const existing = this.forms[workPackageId];
const existing = this.forms[workPackage.id!];
if (existing) {
existing.destroy();
delete this.forms[workPackageId];
delete this.forms[workPackage.id!];
}
}
public startEditing(workPackage:WorkPackageResource, classIdentifier:string):WorkPackageEditForm {
public startEditing(workPackage:WorkPackageResource, classIdentifier:string):EditForm {
const wpId = workPackage.id!;
const existing = this.forms[wpId];
if (existing) {
@ -43,8 +44,7 @@ export class WorkPackageTableEditingContext {
}
// Get any existing edit state for this work package
const editContext = new TableRowEditContext(this.table, this.injector, wpId, classIdentifier);
return this.forms[wpId] = WorkPackageEditForm.createInContext(this.injector, editContext, workPackage, false);
return this.forms[wpId] = new TableEditForm(this.injector, this.table, wpId, classIdentifier);
}
}

@ -28,9 +28,9 @@
import {Component, Injector, Input} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {WorkPackageEditFieldGroupComponent} from 'core-components/wp-edit/wp-edit-field/wp-edit-field-group.directive';
import {FieldDescriptor, GroupDescriptor} from 'core-components/work-packages/wp-single-view/wp-single-view.component';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {EditFormComponent} from "core-app/modules/fields/edit/edit-form/edit-form.component";
@Component({
selector: 'wp-attribute-group',
@ -48,7 +48,7 @@ export class WorkPackageFormAttributeGroupComponent {
};
constructor(readonly I18n:I18nService,
public wpEditFieldGroup:WorkPackageEditFieldGroupComponent,
public wpeditForm:EditFormComponent,
protected injector:Injector) {
}
@ -62,6 +62,6 @@ export class WorkPackageFormAttributeGroupComponent {
*/
public shouldHideField(descriptor:FieldDescriptor) {
const field = descriptor.field || descriptor.fields![0];
return this.wpEditFieldGroup.editMode && !field.writable;
return this.wpeditForm.editMode && !field.writable;
}
}

@ -16,17 +16,16 @@
<div *ngIf="!descriptor.multiple && descriptor.field"
class="attributes-key-value--value-container">
<wp-edit-field *ngIf="descriptor.field!.isFormattable"
<editable-attribute-field *ngIf="descriptor.field!.isFormattable"
class="wp-edit-formattable-field"
[workPackageId]="workPackage.id"
[resource]="workPackage"
[isDropTarget]="true"
[fieldName]="descriptor.name">
</wp-edit-field>
<wp-edit-field *ngIf="!descriptor.field.isFormattable"
[workPackageId]="workPackage.id"
[fieldName]="descriptor.name"
[ngClass]="descriptor.field!.schema.type === 'String' ? 'wp-edit-field--text' : ''">
</wp-edit-field>
</editable-attribute-field>
<editable-attribute-field *ngIf="!descriptor.field.isFormattable"
[resource]="workPackage"
[fieldName]="descriptor.name">
</editable-attribute-field>
</div>
<div
class="attributes-key-value--key"
@ -39,19 +38,19 @@
<div
*ngIf="descriptor.multiple"
class="attributes-key-value--value-container -minimal">
<wp-edit-field [fieldName]="descriptor.fields[0].name"
[workPackageId]="workPackage.id"
<editable-attribute-field [fieldName]="descriptor.fields[0].name"
[resource]="workPackage"
[wrapperClasses]="'-small -shrink'"
[displayPlaceholder]="text[descriptor.name][descriptor.fields[0].name]">
</wp-edit-field>
</editable-attribute-field>
<span class="attributes-key-value--value-separator"></span>
<wp-edit-field [fieldName]="descriptor.fields[1].name"
[workPackageId]="workPackage.id"
<editable-attribute-field [fieldName]="descriptor.fields[1].name"
[resource]="workPackage"
[wrapperClasses]="'-small -shrink'"
[displayPlaceholder]="text[descriptor.name][descriptor.fields[1].name]">
</wp-edit-field>
</editable-attribute-field>
</div>
</ng-template>
</div>

@ -2,7 +2,6 @@ import {Injector} from '@angular/core';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {States} from '../states.service';
import {WorkPackageEditForm} from '../wp-edit-form/work-package-edit-form';
import {
commonRowClassName,
SingleRowBuilder,
@ -13,8 +12,9 @@ import {WorkPackageTable} from '../wp-fast-table/wp-fast-table';
import {WorkPackageViewSelectionService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-selection.service";
import {WorkPackageViewColumnsService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-columns.service";
import {QueryColumn} from "core-components/wp-query/query-column";
import {wpCellTdClassName} from "core-components/wp-fast-table/builders/cell-builder";
import {tdClassName} from "core-components/wp-fast-table/builders/cell-builder";
import {internalContextMenuColumn} from "core-components/wp-fast-table/builders/internal-sort-columns";
import {EditForm} from "core-app/modules/fields/edit/edit-form/edit-form";
export const inlineCreateRowClassName = 'wp-inline-create-row';
export const inlineCreateCancelClassName = 'wp-table--cancel-create-link';
@ -48,7 +48,7 @@ export class InlineCreateRowBuilder extends SingleRowBuilder {
}
}
public buildNew(workPackage:WorkPackageResource, form:WorkPackageEditForm):[HTMLElement, boolean] {
public buildNew(workPackage:WorkPackageResource, form:EditForm):[HTMLElement, boolean] {
// Get any existing edit state for this work package
const [row, hidden] = this.buildEmpty(workPackage);
@ -78,7 +78,7 @@ export class InlineCreateRowBuilder extends SingleRowBuilder {
protected buildCancelButton() {
const td = document.createElement('td');
td.classList.add(wpCellTdClassName, 'wp-table--cancel-create-td');
td.classList.add(tdClassName, 'wp-table--cancel-create-td');
td.innerHTML = `
<a

@ -41,7 +41,6 @@ import {AuthorisationService} from 'core-app/modules/common/model-auth/model-aut
import {WorkPackageViewFocusService} from 'core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-focus.service';
import {filter} from 'rxjs/operators';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageEditForm} from '../wp-edit-form/work-package-edit-form';
import {onClickOrEnter} from '../wp-fast-table/handlers/click-or-enter-handler';
import {WorkPackageTable} from '../wp-fast-table/wp-fast-table';
import {WorkPackageCreateService} from '../wp-new/wp-create.service';
@ -58,6 +57,7 @@ import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/w
import {Subscription} from 'rxjs';
import {WorkPackageViewColumnsService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-columns.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {EditForm} from "core-app/modules/fields/edit/edit-form/edit-form";
@Component({
selector: '[wpInlineCreate]',
@ -81,7 +81,7 @@ export class WorkPackageInlineCreateComponent implements OnInit, AfterViewInit,
private currentWorkPackage:WorkPackageResource | null;
private workPackageEditForm:WorkPackageEditForm | undefined;
private workPackageEditForm:EditForm | undefined;
private editingSubscription:Subscription|undefined;
@ -265,7 +265,7 @@ export class WorkPackageInlineCreateComponent implements OnInit, AfterViewInit,
* @param wp Work package to be rendered
* @returns The work package form of the row
*/
private renderInlineCreateRow(wp:WorkPackageResource):WorkPackageEditForm {
private renderInlineCreateRow(wp:WorkPackageResource):EditForm {
const builder = new InlineCreateRowBuilder(this.injector, this.table);
const form = this.table.editing.startEditing(wp, builder.classIdentifier(wp));

@ -26,23 +26,15 @@
// See doc/COPYRIGHT.rdoc for more details.
// ++
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Inject,
Injectable,
Injector,
OnDestroy,
OnInit
} from '@angular/core';
import {ChangeDetectorRef, Injectable, Injector, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {StateService, Transition} from '@uirouter/core';
import {PathHelperService} from 'core-app/modules/common/path-helper/path-helper.service';
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {componentDestroyed, untilComponentDestroyed} from 'ng2-rx-componentdestroyed';
import {States} from '../states.service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {RootResource} from 'core-app/modules/hal/resources/root-resource';
import {WorkPackageCacheService} from '../work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from '../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageCreateService} from './wp-create.service';
import {takeUntil} from 'rxjs/operators';
import {RootDmService} from 'core-app/modules/hal/dm-services/root-dm.service';
@ -51,6 +43,10 @@ import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {CurrentUserService} from "core-app/components/user/current-user.service";
import {WorkPackageViewFiltersService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-filters.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {WorkPackageViewFocusService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-focus.service";
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
import {EditFormComponent} from "core-app/modules/fields/edit/edit-form/edit-form.component";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Injectable()
@ -68,24 +64,28 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
button_settings: this.I18n.t('js.button_settings')
};
constructor(readonly $transition:Transition,
readonly $state:StateService,
readonly I18n:I18nService,
readonly titleService:OpTitleService,
readonly injector:Injector,
readonly currentUser:CurrentUserService,
protected wpNotificationsService:WorkPackageNotificationService,
protected states:States,
protected wpCreate:WorkPackageCreateService,
protected wpTableFilters:WorkPackageViewFiltersService,
protected wpCacheService:WorkPackageCacheService,
protected pathHelper:PathHelperService,
protected cdRef:ChangeDetectorRef,
protected RootDm:RootDmService) {
@ViewChild(EditFormComponent, {static: false}) private editForm:EditFormComponent|undefined;
constructor(protected readonly $transition:Transition,
protected readonly $state:StateService,
protected readonly I18n:I18nService,
protected readonly titleService:OpTitleService,
protected readonly injector:Injector,
protected readonly notificationService:WorkPackageNotificationService,
protected readonly states:States,
protected readonly wpCreate:WorkPackageCreateService,
protected readonly wpViewFocus:WorkPackageViewFocusService,
protected readonly wpTableFilters:WorkPackageViewFiltersService,
protected readonly wpCacheService:WorkPackageCacheService,
protected readonly pathHelper:PathHelperService,
protected readonly cdRef:ChangeDetectorRef,
protected readonly RootDm:RootDmService) {
}
public ngOnInit() {
this.closeEditFormWhenNewWorkPackageSaved();
this
.createdWorkPackage()
.then((changeset:WorkPackageChangeset) => {
@ -97,7 +97,7 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
if (this.stateParams['parent_id']) {
this.newWorkPackage.parent =
{ href: this.pathHelper.api.v3.work_packages.id(this.stateParams['parent_id']).path };
{href: this.pathHelper.api.v3.work_packages.id(this.stateParams['parent_id']).path};
}
// Load the parent simply to display the type name :-/
@ -123,7 +123,7 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
window.location.href = url.toString();
}
});
this.wpNotificationsService.handleRawError(error);
this.notificationService.handleRawError(error);
}
});
}
@ -136,6 +136,24 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
this.$state.go('work-packages.new', this.$state.params);
}
public onSaved(params:{ savedResource:WorkPackageResource, isInitial:boolean }) {
let {savedResource, isInitial} = params;
// Shouldn't this always be true in create controller?
// Close all edit fields when saving
if (isInitial && this.editForm && this.editForm.editMode) {
this.editForm.stop();
}
if (this.successState) {
this.$state.go(this.successState, {workPackageId: savedResource.id})
.then(() => {
this.wpViewFocus.updateFocus(savedResource.id!);
this.notificationService.showSave(savedResource, isInitial);
});
}
}
protected setTitle() {
this.titleService.setFirstPart(this.I18n.t('js.work_packages.create.title'));
}
@ -151,4 +169,13 @@ export class WorkPackageCreateController implements OnInit, OnDestroy {
return this.wpCreate.createOrContinueWorkPackage(project, type);
}
private closeEditFormWhenNewWorkPackageSaved() {
this.wpCreate
.onNewWorkPackage()
.pipe(untilComponentDestroyed(this))
.subscribe((wp:WorkPackageResource) => {
this.onSaved({savedResource: wp, isInitial: true});
});
}
}

@ -33,14 +33,21 @@ import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-r
import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
import {HookService} from 'core-app/modules/plugins/hook-service';
import {WorkPackageFilterValues} from "core-components/wp-edit-form/work-package-filter-values";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {
HalResourceEditingService,
ResourceChangesetCommit
} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
import {filter} from "rxjs/operators";
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {WorkPackageDmService} from "core-app/modules/hal/dm-services/work-package-dm.service";
import {FormResource} from "core-app/modules/hal/resources/form-resource";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {ResourceChangeset} from "core-app/modules/fields/changeset/resource-changeset";
export const newWorkPackageHref = '/api/v3/work_packages/new';
@Injectable()
export class WorkPackageCreateService implements OnDestroy {
@ -54,17 +61,29 @@ export class WorkPackageCreateService implements OnDestroy {
protected wpCacheService:WorkPackageCacheService,
protected halResourceService:HalResourceService,
protected readonly querySpace:IsolatedQuerySpace,
protected wpEditing:WorkPackageEditingService,
protected halEditing:HalResourceEditingService,
protected workPackageDmService:WorkPackageDmService,
protected readonly wpEvents:WorkPackageEventsService) {
protected readonly halEvents:HalEventsService) {
this.wpEditing
this.halEditing
.comittedChanges
.pipe(
untilComponentDestroyed(this),
filter(commit => commit.wasNew)
filter(commit => commit.resource._type === 'WorkPackage' && commit.wasNew)
)
.subscribe(commit => this.newWorkPackageCreated(commit.workPackage));
.subscribe((commit:ResourceChangesetCommit<WorkPackageResource>) => {
this.newWorkPackageCreated(commit.resource);
});
this.halEditing
.changes$(newWorkPackageHref)
.pipe(
untilComponentDestroyed(this),
filter(changeset => !changeset)
)
.subscribe(() => {
this.reset();
});
}
ngOnDestroy() {
@ -72,8 +91,8 @@ export class WorkPackageCreateService implements OnDestroy {
}
protected newWorkPackageCreated(wp:WorkPackageResource) {
this.form = undefined;
this.wpEvents.push({ type: 'created', id: wp.id! });
this.halEvents.push(wp, { eventType: 'created' });
this.reset();
this.newWorkPackageCreatedSubject.next(wp);
}
@ -93,11 +112,11 @@ export class WorkPackageCreateService implements OnDestroy {
});
}
public fromCreateForm(form:FormResource) {
public fromCreateForm(form:FormResource):WorkPackageChangeset {
let wp = this.halResourceService.createHalResourceOfType<WorkPackageResource>('WorkPackage', form.payload.$plain());
wp.initializeNewResource(form);
const change = this.wpEditing.edit(wp, form);
const change = this.halEditing.edit<WorkPackageResource, WorkPackageChangeset>(wp, form);
// Call work package initialization hook
this.hooks.call('workPackageNewInitialization', change);
@ -128,7 +147,7 @@ export class WorkPackageCreateService implements OnDestroy {
wp.initializeNewResource(form);
return this.wpEditing.edit(wp, form);
return this.halEditing.edit(wp, form);
}
@ -141,15 +160,14 @@ export class WorkPackageCreateService implements OnDestroy {
}
public cancelCreation() {
this.wpEditing.stopEditing('new');
this.wpCacheService.clearSome('new');
this.form = undefined;
this.halEditing.stopEditing({ href: newWorkPackageHref });
this.reset();
}
public changesetUpdates$() {
return this
.wpEditing
.state('new')
.halEditing
.state(newWorkPackageHref)
.values$();
}
@ -160,16 +178,21 @@ export class WorkPackageCreateService implements OnDestroy {
changePromise = this.createNewWithDefaults(projectIdentifier, type);
}
return changePromise.then((change) => {
this.wpEditing.updateValue('new', change);
return changePromise.then((change:WorkPackageChangeset) => {
this.halEditing.updateValue(newWorkPackageHref, change);
this.wpCacheService.updateWorkPackage(change.pristineResource);
return change;
});
}
protected reset() {
this.wpCacheService.clearSome('new');
this.form = undefined;
}
protected continueExistingEdit(type?:number) {
const change = this.wpEditing.state('new').value;
const change = this.halEditing.state(newWorkPackageHref).value as WorkPackageChangeset;
if (change !== undefined) {
const changeType = change.projectedResource.type;

@ -1,9 +1,10 @@
<div
class="work-package--new-state work-packages--new work-packages--show-view toolbar-container"
*ngIf="newWorkPackage">
<wp-edit-field-group [workPackage]="newWorkPackage"
[successState]="successState"
[inEditMode]="true">
class="work-package--new-state work-packages--new work-packages--show-view toolbar-container"
*ngIf="newWorkPackage">
<edit-form [resource]="newWorkPackage"
[skippedFields]="['status', 'type']"
[inEditMode]="true"
(onSaved)="onSaved($event)">
<div class="toolbar">
<div class="title-container">
<wp-type-status [workPackage]="newWorkPackage"></wp-type-status>
@ -26,6 +27,7 @@
<wp-single-view [workPackage]="newWorkPackage"
[showProject]="copying">
</wp-single-view>
<wp-edit-actions-bar (onCancel)="cancelAndBackToList()"></wp-edit-actions-bar>
</wp-edit-field-group>
<wp-edit-actions-bar (onCancel)="cancelAndBackToList()">
</wp-edit-actions-bar>
</edit-form>
</div>

@ -2,10 +2,11 @@
class="work-packages--details work-packages--new"
*ngIf="newWorkPackage"
>
<wp-edit-field-group [workPackage]="newWorkPackage"
[successState]="successState"
[inEditMode]="true">
<div class="work-packages--details-content -create-mode">
<edit-form [resource]="newWorkPackage"
[skippedFields]="['status', 'type']"
[inEditMode]="true"
(onSaved)="onSaved($event)">
<div class="work-packages--details-content -create-mode">
<div class="work-packages--new-details-header">
<wp-type-status [workPackage]="newWorkPackage"></wp-type-status>
<div class="wp--details--switch-fullscreen-wrapper">
@ -21,12 +22,14 @@
</div>
<div class="work-packages--details-toolbar-container">
<wp-edit-actions-bar (onCancel)="cancelAndBackToList()"></wp-edit-actions-bar>
<wp-edit-actions-bar
(onCancel)="cancelAndBackToList()">
</wp-edit-actions-bar>
</div>
<div class="work-packages--details--resizer hidden-for-mobile hide-when-print">
<wp-resizer [elementClass]="'work-packages-split-view--details-side'"
[localStorageKey]="'openProject-splitViewFlexBasis'"></wp-resizer>
</div>
</wp-edit-field-group>
</edit-form>
</div>

@ -43,7 +43,7 @@ import {WorkPackageCacheService} from "core-components/work-packages/work-packag
import {filter} from "rxjs/operators";
import {QueryResource} from "core-app/modules/hal/resources/query-resource";
import {GroupDescriptor} from "core-components/work-packages/wp-single-view/wp-single-view.component";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
@Component({
selector: 'wp-children-query',
@ -74,7 +74,7 @@ export class WorkPackageChildrenQueryComponent extends WorkPackageRelationQueryB
constructor(protected wpRelationsHierarchyService:WorkPackageRelationsHierarchyService,
protected PathHelper:PathHelperService,
protected wpInlineCreate:WorkPackageInlineCreateService,
protected wpEvents:WorkPackageEventsService,
protected halEvents:HalEventsService,
protected wpCacheService:WorkPackageCacheService,
protected queryUrlParamsHelper:UrlParamsHelperService,
readonly I18n:I18nService) {
@ -92,9 +92,8 @@ export class WorkPackageChildrenQueryComponent extends WorkPackageRelationQueryB
this.wpInlineCreate.newInlineWorkPackageCreated
.pipe(untilComponentDestroyed(this))
.subscribe((toId:string) => {
this.wpEvents.push({
type: 'association',
id: this.workPackage.id!,
this.halEvents.push(this.workPackage, {
eventType: 'association',
relatedWorkPackage: toId,
relationType: 'child'
});

@ -31,7 +31,7 @@ import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/wp-inline-create.service";
import {WorkPackageInlineCreateComponent} from "core-components/wp-inline-create/wp-inline-create.component";
import {WorkPackageRelationsService} from "core-components/wp-relations/wp-relations.service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageCacheService} from "core-components/work-packages/work-package-cache.service";
import {WpRelationInlineCreateServiceInterface} from "core-components/wp-relations/embedded/wp-relation-inline-create.service.interface";
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
@ -39,7 +39,8 @@ import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/iso
import {ApiV3Filter} from "core-components/api/api-v3/api-v3-filter-builder";
import {UrlParamsHelperService} from "core-components/wp-query/url-params-helper";
import {RelationResource} from "core-app/modules/hal/resources/relation-resource";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
templateUrl: './wp-relation-inline-add-existing.component.html'
@ -58,8 +59,8 @@ export class WpRelationInlineAddExistingComponent {
@Inject(WorkPackageInlineCreateService) protected readonly wpInlineCreate:WpRelationInlineCreateServiceInterface,
protected wpCacheService:WorkPackageCacheService,
protected wpRelations:WorkPackageRelationsService,
protected wpNotificationsService:WorkPackageNotificationService,
protected wpEvents:WorkPackageEventsService,
protected notificationService:WorkPackageNotificationService,
protected halEvents:HalEventsService,
protected urlParamsHelper:UrlParamsHelperService,
protected querySpace:IsolatedQuerySpace,
protected readonly I18n:I18nService) {
@ -77,9 +78,8 @@ export class WpRelationInlineAddExistingComponent {
.then(() => {
this.wpCacheService.loadWorkPackage(this.workPackage.id!, true);
this.wpEvents.push({
type: 'association',
id: this.workPackage.id!,
this.halEvents.push(this.workPackage, {
eventType: 'association',
relatedWorkPackage: newRelationId,
relationType: this.relationType,
});
@ -89,7 +89,7 @@ export class WpRelationInlineAddExistingComponent {
this.cancel();
})
.catch((err:any) => {
this.wpNotificationsService.handleRawError(err, this.workPackage);
this.notificationService.handleRawError(err, this.workPackage);
this.isDisabled = false;
this.cancel();
});

@ -37,12 +37,12 @@ import {WorkPackageInlineCreateService} from "core-components/wp-inline-create/w
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
import {WorkPackageRelationQueryBase} from "core-components/wp-relations/embedded/wp-relation-query.base";
import {WpRelationInlineCreateService} from "core-components/wp-relations/embedded/relations/wp-relation-inline-create.service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {WorkPackageRelationsService} from "core-components/wp-relations/wp-relations.service";
import {filter} from "rxjs/operators";
import {QueryResource} from "core-app/modules/hal/resources/query-resource";
import {GroupDescriptor} from "core-components/work-packages/wp-single-view/wp-single-view.component";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
selector: 'wp-relation-query',
@ -65,7 +65,7 @@ export class WorkPackageRelationQueryComponent extends WorkPackageRelationQueryB
this.embeddedTable.loadingIndicator = this.wpRelations.require(relatedTo.id!)
.then(() => this.wpInlineCreate.remove(this.workPackage, relatedTo))
.then(() => this.refreshTable())
.catch((error) => this.wpNotifications.handleRawError(error, this.workPackage));
.catch((error) => this.notificationService.handleRawError(error, this.workPackage));
},
(child:WorkPackageResource) => !!child.changeParent
)
@ -74,9 +74,9 @@ export class WorkPackageRelationQueryComponent extends WorkPackageRelationQueryB
constructor(protected readonly PathHelper:PathHelperService,
@Inject(WorkPackageInlineCreateService) protected readonly wpInlineCreate:WpRelationInlineCreateService,
protected readonly wpRelations:WorkPackageRelationsService,
protected readonly wpEvents:WorkPackageEventsService,
protected readonly halEvents:HalEventsService,
protected readonly queryUrlParamsHelper:UrlParamsHelperService,
protected readonly wpNotifications:WorkPackageNotificationService,
protected readonly notificationService:WorkPackageNotificationService,
protected readonly I18n:I18nService) {
super(queryUrlParamsHelper);
}
@ -113,14 +113,13 @@ export class WorkPackageRelationQueryComponent extends WorkPackageRelationQueryB
this.wpInlineCreate
.add(this.workPackage, toId)
.then(() => {
this.wpEvents.push({
type: 'association',
id: this.workPackage.id!,
this.halEvents.push(this.workPackage, {
eventType: 'association',
relatedWorkPackage: toId,
relationType: this.getRelationTypeFromQuery()
});
})
.catch(error => this.wpNotifications.handleRawError(error, this.workPackage));
.catch(error => this.notificationService.handleRawError(error, this.workPackage));
}
private getRelationTypeFromQuery() {

@ -1,5 +1,5 @@
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageRelationsService} from '../wp-relations.service';
import {PathHelperService} from 'core-app/modules/common/path-helper/path-helper.service';
@ -7,7 +7,8 @@ import {RelationResource} from 'core-app/modules/hal/resources/relation-resource
import {ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from "@angular/core";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {untilComponentDestroyed} from "ng2-rx-componentdestroyed";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
@ -56,9 +57,9 @@ export class WorkPackageRelationRowComponent implements OnInit, OnDestroy {
};
constructor(protected wpCacheService:WorkPackageCacheService,
protected wpNotificationsService:WorkPackageNotificationService,
protected notificationService:WorkPackageNotificationService,
protected wpRelations:WorkPackageRelationsService,
protected wpEvents:WorkPackageEventsService,
protected halEvents:HalEventsService,
protected I18n:I18nService,
protected cdRef:ChangeDetectorRef,
protected PathHelper:PathHelperService) {
@ -130,7 +131,7 @@ export class WorkPackageRelationRowComponent implements OnInit, OnDestroy {
this.relation = savedRelation;
this.relatedWorkPackage.relatedBy = savedRelation;
this.userInputs.showDescriptionEditForm = false;
this.wpNotificationsService.showSave(this.relatedWorkPackage);
this.notificationService.showSave(this.relatedWorkPackage);
this.cdRef.detectChanges();
});
}
@ -156,14 +157,14 @@ export class WorkPackageRelationRowComponent implements OnInit, OnDestroy {
this.relation,
this.selectedRelationType.name)
.then((savedRelation:RelationResource) => {
this.wpNotificationsService.showSave(this.relatedWorkPackage);
this.notificationService.showSave(this.relatedWorkPackage);
this.relatedWorkPackage.relatedBy = savedRelation;
this.relation = savedRelation;
this.userInputs.showRelationTypesForm = false;
this.cdRef.detectChanges();
})
.catch((error:any) => this.wpNotificationsService.handleRawError(error, this.workPackage));
.catch((error:any) => this.notificationService.handleRawError(error, this.workPackage));
}
public toggleUserDescriptionForm() {
@ -173,17 +174,16 @@ export class WorkPackageRelationRowComponent implements OnInit, OnDestroy {
public removeRelation() {
this.wpRelations.removeRelation(this.relation)
.then(() => {
this.wpEvents.push({
type: 'association',
id: this.workPackage.id!,
this.halEvents.push(this.workPackage, {
eventType: 'association',
relatedWorkPackage: null,
relationType: this.relation.normalizedType(this.workPackage)
});
this.wpCacheService.updateWorkPackage(this.relatedWorkPackage);
this.wpNotificationsService.showSave(this.relatedWorkPackage);
this.notificationService.showSave(this.relatedWorkPackage);
})
.catch((err:any) => this.wpNotificationsService.handleRawError(err,
.catch((err:any) => this.notificationService.handleRawError(err,
this.relatedWorkPackage));
}
}

@ -16,9 +16,9 @@
[textContent]="relatedWorkPackage.type.name"></span>
<span class="hidden-for-sighted" [textContent]="text.updateRelation"></span>
</span>
<div class="wp-edit-field inplace-edit"
<div class="inline-edit--container inplace-edit"
*ngIf="userInputs.showRelationTypesForm">
<select class="wp-inline-edit--field form--select"
<select class="inline-edit--field form--select"
[(ngModel)]="selectedRelationType"
(change)="saveRelationType()"
role="listbox"
@ -42,9 +42,9 @@
</div>
<div class="grid-content medium-3 collapse wp-relations-status-field">
<wp-edit-field-group *ngIf="relatedWorkPackage" [workPackage]="relatedWorkPackage">
<wp-edit-field [workPackageId]="relatedWorkPackage.id" fieldName="status"></wp-edit-field>
</wp-edit-field-group>
<edit-form *ngIf="relatedWorkPackage" [resource]="relatedWorkPackage">
<editable-attribute-field [resource]="relatedWorkPackage" fieldName="status"></editable-attribute-field>
</edit-form>
</div>
<div class="grid-content medium-2 collapse wp-relations-controls-section"

@ -40,7 +40,7 @@ import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {from, Observable, of, Subject} from "rxjs";
import {catchError, debounceTime, distinctUntilChanged, map, switchMap, tap} from "rxjs/operators";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {NgSelectComponent} from "@ng-select/ng-select";
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {PathHelperService} from "core-app/modules/common/path-helper/path-helper.service";
@ -49,6 +49,7 @@ import {CurrentProjectService} from "core-components/projects/current-project.se
import {ApiV3Filter, ApiV3FilterBuilder} from "core-components/api/api-v3/api-v3-filter-builder";
import {HalResourceService} from "core-app/modules/hal/services/hal-resource.service";
import {SchemaCacheService} from "core-components/schemas/schema-cache.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
selector: 'wp-relations-autocomplete',
@ -94,7 +95,7 @@ export class WorkPackageRelationsAutocomplete implements AfterContentInit {
constructor(private readonly querySpace:IsolatedQuerySpace,
private readonly pathHelper:PathHelperService,
private readonly wpNotificationsService:WorkPackageNotificationService,
private readonly notificationService:WorkPackageNotificationService,
private readonly CurrentProject:CurrentProjectService,
private readonly halResourceService:HalResourceService,
private readonly schemaCacheService:SchemaCacheService,
@ -152,7 +153,7 @@ export class WorkPackageRelationsAutocomplete implements AfterContentInit {
.pipe(
map(collection => collection.elements),
catchError((error:unknown) => {
this.wpNotificationsService.handleRawError(error);
this.notificationService.handleRawError(error);
return of([]);
}),
tap(() => this.isLoading = false)

@ -1,11 +1,11 @@
import {RelationResource} from 'core-app/modules/hal/resources/relation-resource';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {WorkPackageRelationsService} from '../wp-relations.service';
import {Component, ElementRef, Inject, Input, ViewChild} from "@angular/core";
import {Component, Input} from "@angular/core";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
selector: 'wp-relations-create',
@ -29,8 +29,8 @@ export class WorkPackageRelationsCreateComponent {
constructor(readonly I18n:I18nService,
protected wpRelations:WorkPackageRelationsService,
protected wpNotificationsService:WorkPackageNotificationService,
protected wpEvents:WorkPackageEventsService,
protected notificationService:WorkPackageNotificationService,
protected halEvents:HalEventsService,
protected wpCacheService:WorkPackageCacheService) {
}
@ -59,17 +59,16 @@ export class WorkPackageRelationsCreateComponent {
this.selectedRelationType,
this.selectedWpId)
.then(relation => {
this.wpEvents.push({
type: 'association',
id: this.workPackage.id!,
this.halEvents.push(this.workPackage, {
eventType: 'association',
relatedWorkPackage: relation.id!,
relationType: this.selectedRelationType
});
this.wpNotificationsService.showSave(this.workPackage);
this.notificationService.showSave(this.workPackage);
this.toggleRelationsCreateForm();
})
.catch(err => {
this.wpNotificationsService.handleRawError(err, this.workPackage);
this.notificationService.handleRawError(err, this.workPackage);
this.toggleRelationsCreateForm();
});
}

@ -28,19 +28,19 @@
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {WorkPackageNotificationService} from 'core-components/wp-edit/wp-notification.service';
import {States} from '../../states.service';
import {StateService} from '@uirouter/core';
import {Injectable} from '@angular/core';
import {PathHelperService} from 'core-app/modules/common/path-helper/path-helper.service';
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Injectable()
export class WorkPackageRelationsHierarchyService {
constructor(protected $state:StateService,
protected states:States,
protected wpEvents:WorkPackageEventsService,
protected wpNotificationsService:WorkPackageNotificationService,
protected halEvents:HalEventsService,
protected notificationService:WorkPackageNotificationService,
protected pathHelper:PathHelperService,
protected wpCacheService:WorkPackageCacheService) {
@ -69,10 +69,9 @@ export class WorkPackageRelationsHierarchyService {
.changeParent(payload)
.then((wp:WorkPackageResource) => {
this.wpCacheService.updateWorkPackage(wp);
this.wpNotificationsService.showSave(wp);
this.wpEvents.push({
type: 'association',
id: workPackage.id!,
this.notificationService.showSave(wp);
this.halEvents.push(workPackage, {
eventType: 'association',
relatedWorkPackage: parentId,
relationType: 'parent'
});
@ -80,7 +79,7 @@ export class WorkPackageRelationsHierarchyService {
return wp;
})
.catch((error) => {
this.wpNotificationsService.handleRawError(error, workPackage);
this.notificationService.handleRawError(error, workPackage);
return Promise.reject(error);
});
}
@ -96,9 +95,8 @@ export class WorkPackageRelationsHierarchyService {
return this.changeParent(wpToBecomeChild!, workPackage.id!)
.then(wp => {
this.wpCacheService.loadWorkPackage(workPackage.id!, true);
this.wpEvents.push({
type: 'association',
id: workPackage.id!,
this.halEvents.push(workPackage, {
eventType: 'association',
relatedWorkPackage: wpToBecomeChild!.id!,
relationType: 'child'
});
@ -141,7 +139,7 @@ export class WorkPackageRelationsHierarchyService {
this.wpCacheService.updateWorkPackage(wp);
})
.catch((error) => {
this.wpNotificationsService.handleRawError(error, childWorkPackage);
this.notificationService.handleRawError(error, childWorkPackage);
return Promise.reject(error);
});
});

@ -32,13 +32,14 @@ import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-r
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
import {LoadingIndicatorService} from 'core-app/modules/common/loading-indicator/loading-indicator.service';
import {WorkPackageCacheService} from 'core-components/work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from 'core-components/wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {componentDestroyed} from 'ng2-rx-componentdestroyed';
import {takeUntil} from 'rxjs/operators';
import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {WorkPackageWatchersService} from 'core-components/wp-single-view-tabs/watchers-tab/wp-watchers.service';
import {PathHelperService} from "core-app/modules/common/path-helper/path-helper.service";
import {AngularTrackingHelpers} from "core-components/angular/tracking-functions";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
templateUrl: './watchers-tab.html',
@ -71,7 +72,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
readonly elementRef:ElementRef,
readonly wpWatchersService:WorkPackageWatchersService,
readonly $transition:Transition,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly notificationService:WorkPackageNotificationService,
readonly loadingIndicator:LoadingIndicatorService,
readonly wpCacheService:WorkPackageCacheService,
readonly cdRef:ChangeDetectorRef,
@ -112,7 +113,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
this.cdRef.detectChanges();
})
.catch((error:any) => {
this.wpNotificationsService.showError(error, this.workPackage);
this.notificationService.showError(error, this.workPackage);
});
}
@ -130,7 +131,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
this.wpCacheService.loadWorkPackage(this.workPackage.id!, true);
this.cdRef.detectChanges();
})
.catch((error:any) => this.wpNotificationsService.showError(error, this.workPackage));
.catch((error:any) => this.notificationService.showError(error, this.workPackage));
}
public removeWatcher(watcher:any) {
@ -146,7 +147,7 @@ export class WorkPackageWatchersTabComponent implements OnInit, OnDestroy {
this.wpCacheService.loadWorkPackage(this.workPackage.id!, true);
this.cdRef.detectChanges();
})
.catch((error:any) => this.wpNotificationsService.showError(error, this.workPackage));
.catch((error:any) => this.notificationService.showError(error, this.workPackage));
}
ngOnDestroy() {

@ -1,12 +1,16 @@
import {
ApplicationRef, ChangeDetectorRef,
ApplicationRef,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ElementRef, EventEmitter,
Inject, InjectionToken,
ElementRef,
EventEmitter,
Inject,
InjectionToken,
Injector,
OnDestroy,
OnInit, Optional,
OnInit,
Optional,
ViewChild
} from '@angular/core';
import {OpModalLocalsMap} from 'core-components/op-modals/op-modal.types';
@ -16,7 +20,8 @@ import {OpModalComponent} from 'core-components/op-modals/op-modal.component';
import {WpTableConfigurationService} from 'core-components/wp-table/configuration-modal/wp-table-configuration.service';
import {
ActiveTabInterface,
TabComponent, TabInterface,
TabComponent,
TabInterface,
TabPortalOutlet
} from 'core-components/wp-table/configuration-modal/tab-portal-outlet';
import {QueryFormDmService} from 'core-app/modules/hal/dm-services/query-form-dm.service';
@ -24,10 +29,10 @@ import {WorkPackageStatesInitializationService} from 'core-components/wp-list/wp
import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/isolated-query-space";
import {QueryFormResource} from 'core-app/modules/hal/resources/query-form-resource';
import {LoadingIndicatorService} from 'core-app/modules/common/loading-indicator/loading-indicator.service';
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {I18nService} from "core-app/modules/common/i18n/i18n.service";
import {OpModalLocalsToken} from "core-components/op-modals/op-modal.service";
import {ComponentType} from "@angular/cdk/portal";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
export const WpTableConfigurationModalPrependToken = new InjectionToken<ComponentType<any>>('WpTableConfigurationModalPrependComponent');
@ -80,7 +85,7 @@ export class WpTableConfigurationModalComponent extends OpModalComponent impleme
readonly querySpace:IsolatedQuerySpace,
readonly queryFormDm:QueryFormDmService,
readonly wpStatesInitialization:WorkPackageStatesInitializationService,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly notificationService:WorkPackageNotificationService,
readonly wpTableColumns:WorkPackageViewColumnsService,
readonly cdRef:ChangeDetectorRef,
readonly ConfigurationService:ConfigurationService,
@ -155,6 +160,6 @@ export class WpTableConfigurationModalComponent extends OpModalComponent impleme
return form;
})
.catch((error) => this.wpNotificationsService.handleRawError(error));
.catch((error) => this.notificationService.handleRawError(error));
}
}

@ -1,17 +1,18 @@
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
import {TableDragActionService} from "core-components/wp-table/drag-and-drop/actions/table-drag-action.service";
import {WorkPackageViewGroupByService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-group-by.service";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {rowGroupClassName} from "core-components/wp-fast-table/builders/modes/grouped/grouped-classes.constants";
import {locatePredecessorBySelector} from "core-components/wp-fast-table/helpers/wp-table-row-helpers";
import {groupIdentifier} from "core-components/wp-fast-table/builders/modes/grouped/grouped-rows-helpers";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
export class GroupByDragActionService extends TableDragActionService {
private wpTableGroupBy = this.injector.get(WorkPackageViewGroupByService);
private wpEditing = this.injector.get<WorkPackageEditingService>(WorkPackageEditingService);
private wpNotifications = this.injector.get(WorkPackageNotificationService);
private halEditing = this.injector.get<HalResourceEditingService>(HalResourceEditingService);
private halNotification = this.injector.get(HalResourceNotificationService);
public get applies() {
return this.wpTableGroupBy.isEnabled;
@ -26,13 +27,13 @@ export class GroupByDragActionService extends TableDragActionService {
}
public handleDrop(workPackage:WorkPackageResource, el:HTMLElement):Promise<unknown> {
const changeset = this.wpEditing.changeFor(workPackage);
const changeset = this.halEditing.changeFor(workPackage);
const groupedValue = this.getValueForGroup(el);
changeset.projectedResource[this.groupedAttribute!] = groupedValue;
return this.wpEditing
return this.halEditing
.save(changeset)
.catch(e => this.wpNotifications.handleRawError(e, workPackage));
.catch(e => this.halNotification.handleRawError(e, workPackage));
}
private getValueForGroup(el:HTMLElement):unknown|null {

@ -29,7 +29,7 @@
import {Injector} from '@angular/core';
import * as moment from 'moment';
import {WorkPackageCacheService} from '../../../work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from '../../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageTimelineTableController} from '../container/wp-timeline-container.directive';
import {RenderInfo} from '../wp-timeline';
import {TimelineCellRenderer} from './timeline-cell-renderer';
@ -38,10 +38,13 @@ import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/iso
import {QueryDmService} from 'core-app/modules/hal/dm-services/query-dm.service';
import {keyCodes} from 'core-app/modules/common/keyCodes.enum';
import {LoadingIndicatorService} from "core-app/modules/common/loading-indicator/loading-indicator.service";
import {WorkPackageEditingService} from 'core-app/components/wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import Moment = moment.Moment;
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
export const classNameBar = 'bar';
export const classNameLeftHandle = 'leftHandle';
@ -54,9 +57,9 @@ export function registerWorkPackageMouseHandler(this:void,
getRenderInfo:() => RenderInfo,
workPackageTimeline:WorkPackageTimelineTableController,
wpCacheService:WorkPackageCacheService,
wpEditing:WorkPackageEditingService,
wpEvents:WorkPackageEventsService,
wpNotificationsService:WorkPackageNotificationService,
halEditing:HalResourceEditingService,
halEvents:HalEventsService,
notificationService:WorkPackageNotificationService,
loadingIndicator:LoadingIndicatorService,
cell:HTMLElement,
bar:HTMLDivElement,
@ -67,7 +70,7 @@ export function registerWorkPackageMouseHandler(this:void,
const querySpace:IsolatedQuerySpace = injector.get(IsolatedQuerySpace);
let mouseDownStartDay:number | null = null; // also flag to signal active drag'n'drop
renderInfo.change = wpEditing.changeFor(renderInfo.workPackage);
renderInfo.change = halEditing.changeFor(renderInfo.workPackage) as WorkPackageChangeset;
let dateStates:any;
let placeholderForEmptyCell:HTMLElement;
@ -245,19 +248,19 @@ export function registerWorkPackageMouseHandler(this:void,
// Remember the time before saving the work package to know which work packages to update
const updatedAt = moment().toISOString();
return loadingIndicator.table.promise = wpEditing.save(change)
return loadingIndicator.table.promise = halEditing.save<WorkPackageResource, WorkPackageChangeset>(change)
.then((result) => {
wpNotificationsService.showSave(result.workPackage);
notificationService.showSave(result.resource);
const ids = _.map(querySpace.rendered.value!, row => row.workPackageId);
loadingIndicator.table.promise =
queryDm.loadIdsUpdatedSince(ids, updatedAt).then(workPackageCollection => {
wpCacheService.updateWorkPackageList(workPackageCollection.elements);
wpEvents.push({ type: 'updated', id: result.workPackage.id! });
halEvents.push(result.resource, { eventType: 'updated' });
});
})
.catch((error) => {
wpNotificationsService.handleRawError(error, renderInfo.workPackage);
notificationService.handleRawError(error, renderInfo.workPackage);
});
}
}

@ -28,7 +28,7 @@
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {States} from '../../../states.service';
import {WorkPackageCacheService} from '../../../work-packages/work-package-cache.service';
import {WorkPackageNotificationService} from '../../../wp-edit/wp-notification.service';
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageTimelineTableController} from '../container/wp-timeline-container.directive';
import {RenderInfo} from '../wp-timeline';
import {TimelineCellRenderer} from './timeline-cell-renderer';
@ -36,8 +36,10 @@ import {TimelineMilestoneCellRenderer} from './timeline-milestone-cell-renderer'
import {registerWorkPackageMouseHandler} from './wp-timeline-cell-mouse-handler';
import {Injector} from '@angular/core';
import {LoadingIndicatorService} from "core-app/modules/common/loading-indicator/loading-indicator.service";
import {WorkPackageEditingService} from 'core-app/components/wp-edit-form/work-package-editing-service';
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
export const classNameLeftLabel = 'labelLeft';
export const classNameRightContainer = 'containerRight';
@ -63,9 +65,9 @@ export class WorkPackageCellLabels {
export class WorkPackageTimelineCell {
readonly wpCacheService:WorkPackageCacheService = this.injector.get(WorkPackageCacheService);
readonly wpEditing:WorkPackageEditingService = this.injector.get(WorkPackageEditingService);
readonly wpEvents:WorkPackageEventsService = this.injector.get(WorkPackageEventsService);
readonly wpNotificationsService:WorkPackageNotificationService = this.injector.get(WorkPackageNotificationService);
readonly halEditing:HalResourceEditingService = this.injector.get(HalResourceEditingService);
readonly halEvents:HalEventsService = this.injector.get(HalEventsService);
readonly notificationService:WorkPackageNotificationService = this.injector.get(WorkPackageNotificationService);
readonly states:States = this.injector.get(States);
readonly loadingIndicator:LoadingIndicatorService = this.injector.get(LoadingIndicatorService);
@ -161,9 +163,9 @@ export class WorkPackageTimelineCell {
() => this.latestRenderInfo,
this.workPackageTimeline,
this.wpCacheService,
this.wpEditing,
this.wpEvents,
this.wpNotificationsService,
this.halEditing,
this.halEvents,
this.notificationService,
this.loadingIndicator,
cell[0],
this.wpElement,

@ -33,14 +33,16 @@ import {RenderInfo} from '../wp-timeline';
import {TimelineCellRenderer} from './timeline-cell-renderer';
import {TimelineMilestoneCellRenderer} from './timeline-milestone-cell-renderer';
import {WorkPackageTimelineCell} from './wp-timeline-cell';
import {WorkPackageEditingService} from 'core-app/components/wp-edit-form/work-package-editing-service';
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {RenderedWorkPackage} from "core-app/modules/work_packages/render-info/rendered-work-package.type";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
export class WorkPackageTimelineCellsRenderer {
// Injections
public states = this.injector.get(States);
public wpEditing = this.injector.get(WorkPackageEditingService);
public halEditing = this.injector.get(HalResourceEditingService);
public cells:{ [classIdentifier:string]:WorkPackageTimelineCell } = {};
@ -142,7 +144,7 @@ export class WorkPackageTimelineCellsRenderer {
return {
viewParams: this.wpTimeline.viewParameters,
workPackage: wp,
change: this.wpEditing.changeFor(wp)
change: this.halEditing.changeFor(wp) as WorkPackageChangeset
};
}
}

@ -50,7 +50,7 @@ import {WorkPackageTimelineCellsRenderer} from "core-components/wp-table/timelin
import {States} from "core-components/states.service";
import {WorkPackagesTableController} from "core-components/wp-table/wp-table.directive";
import {WorkPackageViewTimelineService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-timeline.service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {WorkPackageRelationsService} from "core-components/wp-relations/wp-relations.service";
import {WorkPackageViewHierarchiesService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-hierarchy.service";
import {WorkPackageTimelineState} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-table-timeline";
@ -58,7 +58,8 @@ import {WorkPackageTimelineCell} from "core-components/wp-table/timeline/cells/w
import {selectorTimelineSide} from "core-components/wp-table/wp-table-scroll-sync";
import {debugLog, timeOutput} from "core-app/helpers/debug_output";
import {RenderedWorkPackage} from "core-app/modules/work_packages/render-info/rendered-work-package.type";
import {WorkPackageEventsService} from "core-app/modules/work_packages/events/work-package-events.service";
import {HalEventsService} from "core-app/modules/hal/services/hal-events.service";
import {WorkPackageNotificationService} from "core-app/modules/work_packages/notifications/work-package-notification.service";
@Component({
selector: 'wp-timeline-container',
@ -100,10 +101,10 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
public wpTableDirective:WorkPackagesTableController,
private NotificationsService:NotificationsService,
private wpTableTimeline:WorkPackageViewTimelineService,
private wpNotificationsService:WorkPackageNotificationService,
private notificationService:WorkPackageNotificationService,
private wpRelations:WorkPackageRelationsService,
private wpTableHierarchies:WorkPackageViewHierarchiesService,
private wpEvents:WorkPackageEventsService,
private halEvents:HalEventsService,
readonly I18n:I18nService) {
}
@ -265,14 +266,13 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
this.wpRelations
.addCommonRelation(start.id!, 'follows', end.id!)
.then(() => {
this.wpEvents.push({
type: 'association',
id: start.id!,
this.halEvents.push(start, {
eventType: 'association',
relatedWorkPackage: end.id!,
relationType: 'follows'
});
})
.catch((error:any) => this.wpNotificationsService.handleRawError(error, end));
.catch((error:any) => this.notificationService.handleRawError(error, end));
});
}
@ -281,14 +281,13 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
this.wpRelations
.addCommonRelation(start.id!, 'precedes', end.id!)
.then(() => {
this.wpEvents.push({
type: 'association',
id: start.id!,
this.halEvents.push(start, {
eventType: 'association',
relatedWorkPackage: end.id!,
relationType: 'precedes'
});
})
.catch((error:any) => this.wpNotificationsService.handleRawError(error, end));
.catch((error:any) => this.notificationService.handleRawError(error, end));
});
}

@ -61,6 +61,7 @@ import {WpTableHoverSync} from "core-components/wp-table/wp-table-hover-sync";
import {WorkPackageTimelineTableController} from "core-components/wp-table/timeline/container/wp-timeline-container.directive";
import {WorkPackageTable} from "core-components/wp-fast-table/wp-fast-table";
import {WorkPackageViewTimelineService} from "core-app/modules/work_packages/routing/wp-view-base/view-services/wp-view-timeline.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
@Component({
templateUrl: './wp-table.directive.html',

@ -11,11 +11,11 @@ import {
tap
} from "rxjs/operators";
import {RequestSwitchmapHandler} from "core-app/helpers/rxjs/request-switchmap";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
export type RequestErrorHandler = (error:unknown) => void;
export function errorNotificationHandler(service:WorkPackageNotificationService):RequestErrorHandler {
export function errorNotificationHandler(service:HalResourceNotificationService):RequestErrorHandler {
return (error:unknown) => service.handleRawError(error);
}

@ -31,7 +31,7 @@ import {I18nService} from 'core-app/modules/common/i18n/i18n.service';
import {PathHelperService} from 'core-app/modules/common/path-helper/path-helper.service';
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
import {States} from 'core-components/states.service';
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
@Component({
selector: 'attachment-list-item',
@ -53,7 +53,7 @@ export class AttachmentListItemComponent {
removeFile: (arg:any) => this.I18n.t('js.label_remove_file', arg)
};
constructor(protected wpNotificationsService:WorkPackageNotificationService,
constructor(protected halNotification:HalResourceNotificationService,
readonly I18n:I18nService,
readonly states:States,
readonly pathHelper:PathHelperService) {

@ -3,7 +3,7 @@
draggable="true"
(dragstart)="setDragData($event)"
[title]="text.dragHint"
focusWithinSelector=".inplace-edit--icon-wrapper">
focusWithinSelector=".inplace-editing--trigger-icon">
<span class="form--selected-value">
<op-icon icon-classes="icon-context icon-attachment"></op-icon>
<a

@ -14,7 +14,7 @@ import {VersionAutocompleterComponent} from "core-app/modules/common/autocomplet
import {OpContextMenuItem} from "core-components/op-context-menu/op-context-menu.types";
import {LinkHandling} from "core-app/modules/common/link-handling/link-handling";
import {StateService} from "@uirouter/core";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {VersionCacheService} from "core-components/versions/version-cache.service";
import {VersionBoardHeaderComponent} from "core-app/modules/boards/board/board-actions/version/version-board-header.component";
import {FormResource} from "core-app/modules/hal/resources/form-resource";
@ -29,7 +29,7 @@ export class BoardVersionActionService implements BoardActionService {
protected versionDm:VersionDmService,
protected versionCache:VersionCacheService,
protected currentProject:CurrentProjectService,
protected wpNotifications:WorkPackageNotificationService,
protected halNotification:HalResourceNotificationService,
protected state:StateService,
protected formCache:FormsCacheService,
protected pathHelper:PathHelperService) {
@ -188,7 +188,7 @@ export class BoardVersionActionService implements BoardActionService {
this.versionCache.updateValue(version.id!, version);
this.state.go('.', {}, { reload: true });
})
.catch(error => this.wpNotifications.handleRawError(error));
.catch(error => this.halNotification.handleRawError(error));
}
private buildItemsForVersion(version:VersionResource):OpContextMenuItem[] {

@ -36,9 +36,10 @@ import {ApiV3Filter} from "core-components/api/api-v3/api-v3-filter-builder";
import {BoardService} from "app/modules/boards/board/board.service";
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource";
import {WorkPackageFilterValues} from "core-components/wp-edit-form/work-package-filter-values";
import {WorkPackageEditingService} from "core-components/wp-edit-form/work-package-editing-service";
import {HalResourceEditingService} from "core-app/modules/fields/edit/services/hal-resource-editing.service";
import {WorkPackageCacheService} from "core-components/work-packages/work-package-cache.service";
import {WorkPackageNotificationService} from "core-components/wp-edit/wp-notification.service";
import {HalResourceNotificationService} from "core-app/modules/hal/services/hal-resource-notification.service";
import {BoardActionsRegistryService} from "core-app/modules/boards/board/board-actions/board-actions-registry.service";
import {BoardActionService} from "core-app/modules/boards/board/board-actions/board-action.service";
import {ComponentType} from "@angular/cdk/portal";
@ -47,6 +48,7 @@ import {CausedUpdatesService} from "core-app/modules/boards/board/caused-updates
import {BoardListMenuComponent} from "core-app/modules/boards/board/board-list/board-list-menu.component";
import {debugLog} from "core-app/helpers/debug_output";
import {WorkPackageCardDragAndDropService} from "core-components/wp-card-view/services/wp-card-drag-and-drop.service";
import {WorkPackageChangeset} from "core-components/wp-edit/work-package-changeset";
export interface DisabledButtonPlaceholder {
text:string;
@ -126,12 +128,12 @@ export class BoardListComponent extends AbstractWidgetComponent implements OnIni
private readonly boardCache:BoardCacheService,
private readonly notifications:NotificationsService,
private readonly querySpace:IsolatedQuerySpace,
private readonly wpNotificationService:WorkPackageNotificationService,
private readonly halNotification:HalResourceNotificationService,
private readonly wpStatesInitialization:WorkPackageStatesInitializationService,
private readonly authorisationService:AuthorisationService,
private readonly wpInlineCreate:WorkPackageInlineCreateService,
protected readonly injector:Injector,
private readonly wpEditing:WorkPackageEditingService,
private readonly halEditing:HalResourceEditingService,
private readonly loadingIndicator:LoadingIndicatorService,
private readonly wpCacheService:WorkPackageCacheService,
private readonly boardService:BoardService,
@ -142,8 +144,8 @@ export class BoardListComponent extends AbstractWidgetComponent implements OnIni
ngOnInit():void {
// Unset the isNew flag
this.initiallyFocused = this.resource.isNew;
this.resource.isNew = false;
this.initiallyFocused = this.resource.isNewWidget;
this.resource.isNewWidget = false;
// Update permission on model updates
this.authorisationService
@ -315,7 +317,7 @@ export class BoardListComponent extends AbstractWidgetComponent implements OnIni
*/
private addWorkPackage(workPackage:WorkPackageResource) {
let query = this.querySpace.query.value!;
const changeset = this.wpEditing.changeFor(workPackage);
const changeset = this.halEditing.changeFor(workPackage) as WorkPackageChangeset;
// Ensure attribute remains writable in the form
const actionAttribute = this.board.actionAttribute;
@ -334,7 +336,7 @@ export class BoardListComponent extends AbstractWidgetComponent implements OnIni
return this.wpCacheService.updateWorkPackage(workPackage);
} else {
// Save changes to the work package, which reloads it as well
return this.wpEditing.save(changeset);
return this.halEditing.save(changeset);
}
}
@ -352,7 +354,7 @@ export class BoardListComponent extends AbstractWidgetComponent implements OnIni
observable
.subscribe(
query => this.wpStatesInitialization.updateQuerySpace(query, query.results),
error => this.loadingError = this.wpNotificationService.retrieveErrorMessage(error)
error => this.loadingError = this.halNotification.retrieveErrorMessage(error)
);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save