decidim 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim might be problematic. Click here for more details.

Files changed (313) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +4 -5
  3. data/.eslintignore +2 -0
  4. data/.eslintrc.json +2 -0
  5. data/.gitignore +1 -0
  6. data/.inch.yml +5 -0
  7. data/.mention-bot +8 -0
  8. data/.rubocop.yml +8 -31
  9. data/.ruby-version +1 -1
  10. data/.travis.yml +24 -14
  11. data/Dockerfile +1 -3
  12. data/Gemfile +1 -3
  13. data/Gemfile.lock +175 -138
  14. data/README.md +63 -5
  15. data/Rakefile +1 -1
  16. data/codecov.yml +1 -0
  17. data/decidim-admin/Rakefile +1 -1
  18. data/decidim-admin/app/assets/javascripts/decidim/admin/application.js.es6 +0 -1
  19. data/decidim-admin/app/assets/stylesheets/decidim/admin/_foundation_and_overrides.scss +1 -0
  20. data/decidim-admin/app/assets/stylesheets/decidim/admin/_icons.scss +9 -0
  21. data/decidim-admin/app/assets/stylesheets/decidim/admin/application.scss +1 -0
  22. data/decidim-admin/app/commands/decidim/admin/create_feature.rb +3 -1
  23. data/decidim-admin/app/commands/decidim/admin/create_participatory_process.rb +26 -14
  24. data/decidim-admin/app/commands/decidim/admin/destroy_feature.rb +5 -0
  25. data/decidim-admin/app/commands/decidim/admin/destroy_participatory_process_step.rb +29 -0
  26. data/decidim-admin/app/commands/decidim/admin/update_feature.rb +47 -0
  27. data/decidim-admin/app/commands/decidim/admin/update_organization.rb +3 -1
  28. data/decidim-admin/app/controllers/decidim/admin/features_controller.rb +37 -2
  29. data/decidim-admin/app/controllers/decidim/admin/participatory_process_step_activations_controller.rb +0 -16
  30. data/decidim-admin/app/controllers/decidim/admin/participatory_process_steps_controller.rb +10 -3
  31. data/decidim-admin/app/controllers/decidim/admin/static_pages_controller.rb +4 -4
  32. data/decidim-admin/app/controllers/decidim/admin/user_groups_controller.rb +32 -0
  33. data/decidim-admin/app/controllers/decidim/admin/users_controller.rb +87 -0
  34. data/decidim-admin/app/forms/decidim/admin/category_form.rb +1 -7
  35. data/decidim-admin/app/forms/decidim/admin/feature_form.rb +26 -0
  36. data/decidim-admin/app/forms/decidim/admin/organization_form.rb +2 -0
  37. data/decidim-admin/app/forms/decidim/admin/participatory_process_step_form.rb +1 -1
  38. data/decidim-admin/app/forms/decidim/admin/static_page_form.rb +2 -3
  39. data/decidim-admin/app/models/decidim/admin/abilities/admin_user.rb +6 -0
  40. data/decidim-admin/app/views/decidim/admin/features/_feature.html.erb +4 -1
  41. data/decidim-admin/app/views/decidim/admin/features/_form.html.erb +49 -0
  42. data/decidim-admin/app/views/decidim/admin/features/_settings_fields.html.erb +5 -0
  43. data/decidim-admin/app/views/decidim/admin/features/edit.html.erb +9 -0
  44. data/decidim-admin/app/views/decidim/admin/features/index.html.erb +6 -0
  45. data/decidim-admin/app/views/decidim/admin/features/new.html.erb +1 -1
  46. data/decidim-admin/app/views/decidim/admin/organization/_form.html.erb +8 -0
  47. data/decidim-admin/app/views/decidim/admin/participatory_process_attachments/_form.html.erb +1 -1
  48. data/decidim-admin/app/views/decidim/admin/participatory_process_steps/index.html.erb +2 -6
  49. data/decidim-admin/app/views/decidim/admin/user_groups/index.html.erb +32 -0
  50. data/decidim-admin/app/views/decidim/admin/users/_form.html.erb +6 -0
  51. data/decidim-admin/app/views/decidim/admin/users/index.html.erb +54 -0
  52. data/decidim-admin/app/views/decidim/admin/users/new.html.erb +11 -0
  53. data/decidim-admin/app/views/layouts/decidim/admin/_sidebar.html.erb +2 -0
  54. data/decidim-admin/app/views/layouts/decidim/admin/participatory_process.html.erb +1 -1
  55. data/decidim-admin/config/i18n-tasks.yml +1 -0
  56. data/decidim-admin/config/locales/ca.yml +103 -5
  57. data/decidim-admin/config/locales/en.yml +57 -4
  58. data/decidim-admin/config/locales/es.yml +103 -5
  59. data/decidim-admin/config/routes.rb +11 -0
  60. data/decidim-admin/decidim-admin.gemspec +2 -3
  61. data/decidim-admin/lib/decidim/admin/features/base_controller.rb +7 -3
  62. data/decidim-admin/lib/decidim/admin/test/factories.rb +8 -0
  63. data/decidim-admin/spec/commands/create_category_spec.rb +2 -1
  64. data/decidim-admin/spec/commands/create_feature_spec.rb +21 -2
  65. data/decidim-admin/spec/commands/create_participatory_process_spec.rb +13 -1
  66. data/decidim-admin/spec/commands/create_static_page_spec.rb +1 -1
  67. data/decidim-admin/spec/commands/destroy_participatory_process_step_spec.rb +45 -0
  68. data/decidim-admin/spec/commands/update_category_spec.rb +2 -1
  69. data/decidim-admin/spec/commands/update_feature_spec.rb +79 -0
  70. data/decidim-admin/spec/commands/update_organization_spec.rb +3 -2
  71. data/decidim-admin/spec/commands/update_static_page_spec.rb +3 -2
  72. data/decidim-admin/spec/factories.rb +2 -9
  73. data/decidim-admin/spec/features/admin_manages_features_spec.rb +84 -2
  74. data/decidim-admin/spec/features/admin_manages_organization_admins_spec.rb +71 -0
  75. data/decidim-admin/spec/features/admin_manages_user_groups_spec.rb +24 -0
  76. data/decidim-admin/spec/forms/category_form_spec.rb +3 -7
  77. data/decidim-admin/spec/forms/organization_form_spec.rb +8 -2
  78. data/decidim-admin/spec/forms/participatory_process_form_spec.rb +2 -1
  79. data/decidim-admin/spec/forms/participatory_process_step_form_spec.rb +2 -21
  80. data/decidim-admin/spec/forms/scope_form_spec.rb +1 -1
  81. data/decidim-admin/spec/forms/static_page_form_spec.rb +2 -7
  82. data/decidim-admin/spec/models/abilities/admin_user_spec.rb +22 -0
  83. data/decidim-admin/spec/shared/manage_process_attachments_examples.rb +2 -1
  84. data/decidim-admin/spec/shared/manage_process_steps_examples.rb +2 -15
  85. data/decidim-admin/spec/spec_helper.rb +3 -1
  86. data/decidim-api/Rakefile +1 -1
  87. data/decidim-api/decidim-api.gemspec +3 -3
  88. data/decidim-api/spec/factories.rb +2 -2
  89. data/decidim-api/spec/spec_helper.rb +3 -1
  90. data/decidim-comments/Rakefile +1 -1
  91. data/decidim-comments/app/assets/javascripts/decidim/comments/bundle.js +0 -0
  92. data/decidim-comments/app/commands/decidim/comments/vote_comment.rb +38 -0
  93. data/decidim-comments/app/frontend/application/icon.component.jsx +9 -4
  94. data/decidim-comments/app/frontend/application/icon.component.test.jsx +12 -2
  95. data/decidim-comments/app/frontend/comments/add_comment_form.component.jsx +43 -11
  96. data/decidim-comments/app/frontend/comments/add_comment_form.mutation.graphql +1 -4
  97. data/decidim-comments/app/frontend/comments/comment.component.jsx +67 -7
  98. data/decidim-comments/app/frontend/comments/comment.component.test.jsx +49 -1
  99. data/decidim-comments/app/frontend/comments/comment_data.fragment.graphql +3 -0
  100. data/decidim-comments/app/frontend/comments/comment_order_selector.component.jsx +51 -6
  101. data/decidim-comments/app/frontend/comments/comment_order_selector.component.test.jsx +12 -1
  102. data/decidim-comments/app/frontend/comments/comment_thread.component.jsx +11 -5
  103. data/decidim-comments/app/frontend/comments/comment_thread.component.test.jsx +13 -3
  104. data/decidim-comments/app/frontend/comments/comment_thread.fragment.graphql +1 -3
  105. data/decidim-comments/app/frontend/comments/comments.component.jsx +37 -11
  106. data/decidim-comments/app/frontend/comments/comments.component.test.jsx +44 -7
  107. data/decidim-comments/app/frontend/comments/comments.query.graphql +2 -2
  108. data/decidim-comments/app/frontend/comments/down_vote.fragment.graphql +6 -0
  109. data/decidim-comments/app/frontend/comments/down_vote.mutation.graphql +7 -0
  110. data/decidim-comments/app/frontend/comments/down_vote_button.component.jsx +84 -0
  111. data/decidim-comments/app/frontend/comments/down_vote_button.component.test.jsx +48 -0
  112. data/decidim-comments/app/frontend/comments/up_vote.fragment.graphql +6 -0
  113. data/decidim-comments/app/frontend/comments/up_vote.mutation.graphql +7 -0
  114. data/decidim-comments/app/frontend/comments/up_vote_button.component.jsx +84 -0
  115. data/decidim-comments/app/frontend/comments/up_vote_button.component.test.jsx +48 -0
  116. data/decidim-comments/app/frontend/comments/vote_button.component.jsx +19 -0
  117. data/decidim-comments/app/frontend/comments/vote_button_component.test.jsx +38 -0
  118. data/decidim-comments/app/frontend/support/generate_comments_data.js +7 -2
  119. data/decidim-comments/app/helpers/decidim/comments/comments_helper.rb +1 -1
  120. data/decidim-comments/app/models/decidim/comments/application_record.rb +9 -0
  121. data/decidim-comments/app/models/decidim/comments/comment.rb +19 -4
  122. data/decidim-comments/app/models/decidim/comments/comment_vote.rb +22 -0
  123. data/decidim-comments/app/models/decidim/comments/seed.rb +27 -0
  124. data/decidim-comments/app/queries/decidim/comments/comments_with_replies.rb +88 -0
  125. data/decidim-comments/app/resolvers/decidim/comments/vote_comment_resolver.rb +20 -0
  126. data/decidim-comments/app/types/decidim/comments/comment_mutation_type.rb +19 -0
  127. data/decidim-comments/app/types/decidim/comments/comment_type.rb +38 -2
  128. data/decidim-comments/config/locales/en.yml +1 -0
  129. data/decidim-comments/db/migrate/20161130143508_create_comments.rb +4 -2
  130. data/decidim-comments/db/migrate/20161219150806_create_comment_votes.rb +13 -0
  131. data/decidim-comments/decidim-comments.gemspec +0 -3
  132. data/decidim-comments/lib/decidim/comments/mutation_extensions.rb +9 -0
  133. data/decidim-comments/lib/decidim/comments/query_extensions.rb +3 -5
  134. data/decidim-comments/lib/decidim/comments/test/factories.rb +22 -0
  135. data/decidim-comments/spec/commands/vote_comment_spec.rb +124 -0
  136. data/decidim-comments/spec/factories.rb +2 -9
  137. data/decidim-comments/spec/features/comments_spec.rb +37 -0
  138. data/decidim-comments/spec/models/comment_spec.rb +34 -0
  139. data/decidim-comments/spec/models/comment_vote_spec.rb +44 -0
  140. data/decidim-comments/spec/models/seed_spec.rb +19 -0
  141. data/decidim-comments/spec/queries/comments_with_replies_spec.rb +86 -0
  142. data/decidim-comments/spec/spec_helper.rb +3 -1
  143. data/decidim-comments/spec/support/dummy.rb +1 -1
  144. data/decidim-comments/spec/types/comment_mutation_type_spec.rb +46 -0
  145. data/decidim-comments/spec/types/comment_type_spec.rb +57 -3
  146. data/{decidim-api → decidim-comments}/spec/types/mutation_type_spec.rb +11 -0
  147. data/decidim-dev/README.md +7 -11
  148. data/decidim-dev/decidim-dev.gemspec +5 -4
  149. data/decidim-dev/lib/decidim/dev.rb +20 -0
  150. data/decidim-dev/lib/decidim/dev/assets/Exampledocument.docx +0 -0
  151. data/decidim-dev/lib/decidim/dev/assets/Exampledocument.odt +0 -0
  152. data/decidim-dev/lib/decidim/dev/assets/Exampledocument.pdf +0 -0
  153. data/decidim-dev/lib/decidim/dev/assets/avatar.svg +14 -0
  154. data/decidim-dev/lib/decidim/dev/assets/city.jpeg +0 -0
  155. data/decidim-dev/lib/decidim/dev/assets/city2.jpeg +0 -0
  156. data/decidim-dev/lib/decidim/dev/assets/city3.jpeg +0 -0
  157. data/decidim-dev/lib/decidim/dev/assets/malicious.jpg +0 -0
  158. data/decidim-dev/lib/decidim/{common_rake.rb → dev/common_rake.rb} +1 -1
  159. data/decidim-dev/lib/decidim/{dummy_authorization_handler.rb → dev/dummy_authorization_handler.rb} +4 -4
  160. data/decidim-dev/lib/decidim/{test → dev/test}/authorization_shared_examples.rb +0 -8
  161. data/decidim-dev/lib/decidim/{test → dev/test}/base_spec_helper.rb +4 -1
  162. data/decidim-dev/lib/decidim/{test → dev/test}/i18n_spec.rb +1 -1
  163. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/action_mailer.rb +0 -0
  164. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/active_job.rb +0 -0
  165. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/authenticated_controller_context.rb +0 -0
  166. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/authorization_handlers.rb +1 -1
  167. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/capybara.rb +3 -10
  168. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/database_cleaner.rb +0 -0
  169. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/engine_routes.rb +0 -0
  170. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/factory_girl.rb +0 -0
  171. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/feature.rb +10 -0
  172. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/feature_context.rb +2 -2
  173. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/helpers.rb +4 -0
  174. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/i18n.rb +1 -0
  175. data/decidim-dev/lib/decidim/dev/test/rspec_support/phantomjs_polyfills/bind-polyfill.js +18 -0
  176. data/decidim-dev/lib/decidim/dev/test/rspec_support/phantomjs_polyfills/object-assign-polyfill.js +24 -0
  177. data/decidim-dev/lib/decidim/dev/test/rspec_support/phantomjs_polyfills/promise.js +233 -0
  178. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/translation_helpers.rb +0 -0
  179. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/warden.rb +0 -0
  180. data/decidim-dev/lib/decidim/{test → dev/test}/rspec_support/wisper.rb +0 -0
  181. data/decidim-dev/lib/generators/decidim/dummy_generator.rb +2 -2
  182. data/decidim-dev/lib/generators/decidim/templates/decidim_dev.rb +2 -0
  183. data/decidim-meetings/Rakefile +1 -1
  184. data/decidim-meetings/app/assets/images/decidim/meetings/icon.svg +1 -0
  185. data/decidim-meetings/app/commands/decidim/meetings/admin/create_meeting.rb +2 -0
  186. data/decidim-meetings/app/commands/decidim/meetings/admin/update_meeting.rb +2 -0
  187. data/decidim-meetings/app/controllers/decidim/meetings/meetings_controller.rb +30 -6
  188. data/decidim-meetings/app/forms/decidim/meetings/admin/meeting_form.rb +14 -0
  189. data/decidim-meetings/app/helpers/decidim/meetings/application_helper.rb +10 -0
  190. data/decidim-meetings/app/models/decidim/meetings/meeting.rb +18 -1
  191. data/decidim-meetings/app/services/decidim/meetings/meeting_search.rb +48 -0
  192. data/decidim-meetings/app/views/decidim/meetings/admin/meetings/_form.html.erb +9 -2
  193. data/decidim-meetings/app/views/decidim/meetings/meetings/_filters.html.erb +24 -0
  194. data/decidim-meetings/app/views/decidim/meetings/meetings/_meetings.html.erb +30 -0
  195. data/decidim-meetings/app/views/decidim/meetings/meetings/_tags.html.erb +10 -0
  196. data/decidim-meetings/app/views/decidim/meetings/meetings/index.html.erb +8 -26
  197. data/decidim-meetings/app/views/decidim/meetings/meetings/index.js.erb +2 -0
  198. data/decidim-meetings/app/views/decidim/meetings/meetings/show.html.erb +1 -0
  199. data/decidim-meetings/config/locales/ca.yml +7 -0
  200. data/decidim-meetings/config/locales/en.yml +7 -0
  201. data/decidim-meetings/config/locales/es.yml +7 -0
  202. data/decidim-meetings/db/migrate/20161130121354_create_meetings.rb +2 -0
  203. data/decidim-meetings/decidim-meetings.gemspec +2 -0
  204. data/decidim-meetings/lib/decidim/meetings/feature.rb +7 -2
  205. data/decidim-meetings/lib/decidim/meetings/list_engine.rb +3 -0
  206. data/decidim-meetings/spec/commands/create_meeting_spec.rb +21 -0
  207. data/decidim-meetings/spec/commands/update_meeting_spec.rb +17 -2
  208. data/decidim-meetings/spec/factories.rb +3 -3
  209. data/decidim-meetings/spec/features/explore_meetings_spec.rb +53 -0
  210. data/decidim-meetings/spec/forms/meeting_form_spec.rb +19 -1
  211. data/decidim-meetings/spec/models/meeting_spec.rb +20 -0
  212. data/decidim-meetings/spec/services/meeting_search_spec.rb +146 -0
  213. data/decidim-meetings/spec/shared/admin_shared_context.rb +4 -2
  214. data/decidim-meetings/spec/shared/manage_meetings_examples.rb +5 -2
  215. data/decidim-meetings/spec/spec_helper.rb +1 -1
  216. data/decidim-pages/Rakefile +1 -1
  217. data/decidim-pages/app/assets/images/decidim/pages/icon.svg +3 -0
  218. data/decidim-pages/app/commands/decidim/pages/admin/update_page.rb +1 -2
  219. data/decidim-pages/app/forms/decidim/pages/admin/page_form.rb +0 -1
  220. data/decidim-pages/app/views/decidim/pages/admin/pages/_form.html.erb +0 -1
  221. data/decidim-pages/app/views/decidim/pages/application/show.html.erb +3 -3
  222. data/decidim-pages/config/i18n-tasks.yml +1 -0
  223. data/decidim-pages/config/locales/ca.yml +5 -1
  224. data/decidim-pages/config/locales/en.yml +5 -1
  225. data/decidim-pages/config/locales/es.yml +5 -1
  226. data/decidim-pages/db/migrate/20170110145040_remove_commentable_flag_from_pages.rb +5 -0
  227. data/decidim-pages/lib/decidim/pages/feature.rb +13 -3
  228. data/decidim-pages/spec/commands/update_page_spec.rb +2 -1
  229. data/decidim-pages/spec/factories.rb +2 -2
  230. data/decidim-pages/spec/features/admin_spec.rb +0 -11
  231. data/decidim-pages/spec/features/page_show_spec.rb +13 -10
  232. data/decidim-pages/spec/forms/page_form_spec.rb +4 -4
  233. data/decidim-pages/spec/spec_helper.rb +3 -1
  234. data/decidim-proposals/Rakefile +1 -1
  235. data/decidim-proposals/app/assets/config/decidim_proposals_manifest.css +1 -0
  236. data/decidim-proposals/app/assets/config/decidim_proposals_manifest.js +1 -0
  237. data/decidim-proposals/app/assets/images/decidim/proposals/icon.svg +1 -0
  238. data/decidim-proposals/app/assets/javascripts/decidim/proposals/social_share.js +2 -0
  239. data/decidim-proposals/app/assets/stylesheets/decidim/proposals/social_share.css.scss +14 -0
  240. data/decidim-proposals/app/commands/decidim/proposals/create_proposal.rb +5 -3
  241. data/decidim-proposals/app/controllers/decidim/proposals/admin/proposals_controller.rb +3 -3
  242. data/decidim-proposals/app/controllers/decidim/proposals/proposal_votes_controller.rb +25 -0
  243. data/decidim-proposals/app/controllers/decidim/proposals/proposals_controller.rb +33 -6
  244. data/decidim-proposals/app/forms/decidim/proposals/admin/proposal_form.rb +7 -6
  245. data/decidim-proposals/app/forms/decidim/proposals/proposal_form.rb +6 -6
  246. data/decidim-proposals/app/helpers/decidim/proposals/application_helper.rb +3 -1
  247. data/decidim-proposals/app/helpers/decidim/proposals/proposal_votes_helper.rb +27 -0
  248. data/decidim-proposals/app/models/decidim/proposals/proposal.rb +8 -0
  249. data/decidim-proposals/app/models/decidim/proposals/proposal_vote.rb +20 -0
  250. data/decidim-proposals/app/services/decidim/proposals/proposal_search.rb +39 -11
  251. data/decidim-proposals/app/views/decidim/proposals/admin/proposals/_form.html.erb +2 -2
  252. data/decidim-proposals/app/views/decidim/proposals/proposal_votes/create.js.erb +5 -0
  253. data/decidim-proposals/app/views/decidim/proposals/proposals/_count.html.erb +1 -0
  254. data/decidim-proposals/app/views/decidim/proposals/proposals/_filters.html.erb +26 -0
  255. data/decidim-proposals/app/views/decidim/proposals/proposals/_proposal.html.erb +11 -2
  256. data/decidim-proposals/app/views/decidim/proposals/proposals/_proposals.html.erb +4 -0
  257. data/decidim-proposals/app/views/decidim/proposals/proposals/_share.html.erb +33 -0
  258. data/decidim-proposals/app/views/decidim/proposals/proposals/_vote_button.html.erb +13 -0
  259. data/decidim-proposals/app/views/decidim/proposals/proposals/_votes_count.html.erb +6 -0
  260. data/decidim-proposals/app/views/decidim/proposals/proposals/index.html.erb +11 -11
  261. data/decidim-proposals/app/views/decidim/proposals/proposals/index.js.erb +5 -0
  262. data/decidim-proposals/app/views/decidim/proposals/proposals/show.html.erb +31 -4
  263. data/decidim-proposals/config/i18n-tasks.yml +1 -0
  264. data/decidim-proposals/config/initializers/social_share_button.rb +4 -0
  265. data/decidim-proposals/config/locales/ca.yml +28 -2
  266. data/decidim-proposals/config/locales/en.yml +27 -1
  267. data/decidim-proposals/config/locales/es.yml +28 -2
  268. data/decidim-proposals/db/migrate/20170112115253_create_proposal_votes.rb +12 -0
  269. data/decidim-proposals/db/migrate/20170113114245_add_text_search_indexes.rb +6 -0
  270. data/decidim-proposals/db/migrate/20170118120151_add_counter_cache_votes_to_proposals.rb +5 -0
  271. data/decidim-proposals/decidim-proposals.gemspec +2 -1
  272. data/decidim-proposals/lib/decidim/proposals/engine.rb +8 -1
  273. data/decidim-proposals/lib/decidim/proposals/feature.rb +30 -4
  274. data/decidim-proposals/spec/commands/decidim/proposals/create_proposal_spec.rb +10 -3
  275. data/decidim-proposals/spec/factories.rb +9 -4
  276. data/decidim-proposals/spec/features/admin_manages_proposals_spec.rb +2 -0
  277. data/decidim-proposals/spec/features/process_admin_manages_proposals_spec.rb +2 -0
  278. data/decidim-proposals/spec/features/proposals_spec.rb +41 -31
  279. data/decidim-proposals/spec/features/vote_proposal_spec.rb +78 -0
  280. data/decidim-proposals/spec/forms/decidim/proposals/proposal_form_spec.rb +11 -10
  281. data/decidim-proposals/spec/helpers/proposal_votes_helper_spec.rb +28 -0
  282. data/decidim-proposals/spec/lib/decidim/proposals/feature_spec.rb +1 -1
  283. data/decidim-proposals/spec/models/decidim/proposals/proposal_spec.rb +20 -3
  284. data/decidim-proposals/spec/models/decidim/proposals/proposal_vote_spec.rb +43 -0
  285. data/decidim-proposals/spec/services/decidim/proposals/proposal_search_spec.rb +50 -4
  286. data/decidim-proposals/spec/shared/manage_proposals_examples.rb +1 -1
  287. data/decidim-proposals/spec/spec_helper.rb +1 -1
  288. data/decidim-system/Rakefile +1 -1
  289. data/decidim-system/app/commands/decidim/system/register_organization.rb +13 -12
  290. data/decidim-system/decidim-system.gemspec +2 -3
  291. data/decidim-system/spec/factories.rb +1 -1
  292. data/decidim-system/spec/spec_helper.rb +3 -1
  293. data/docs/social_providers.md +41 -0
  294. data/karma.conf.js +4 -2
  295. data/lib/generators/decidim/app_generator.rb +6 -0
  296. data/lib/generators/decidim/demo_generator.rb +2 -2
  297. data/lib/generators/decidim/install_generator.rb +5 -4
  298. data/lib/generators/decidim/templates/Gemfile.erb +3 -5
  299. data/lib/generators/decidim/templates/initializer.rb +1 -1
  300. data/lib/generators/decidim/templates/secrets.yml.erb +26 -0
  301. data/lib/generators/decidim/templates/social_share_button.rb +7 -0
  302. data/package.json +16 -6
  303. data/webpack.config.js +23 -8
  304. data/yarn.lock +401 -345
  305. metadata +130 -48
  306. data/Gemfile.common +0 -1
  307. data/decidim-admin/Gemfile +0 -6
  308. data/decidim-comments/Gemfile +0 -6
  309. data/decidim-comments/package.json +0 -21
  310. data/decidim-dev/Gemfile +0 -6
  311. data/decidim-dev/lib/decidim/test/rspec_support/bullet.rb +0 -15
  312. data/decidim-dev/lib/generators/decidim/templates/bullet.rb +0 -6
  313. data/decidim-system/Gemfile +0 -6
@@ -1,8 +1,5 @@
1
1
  mutation addComment($commentableId: String!, $commentableType: String!, $body: String!, $alignment: Int) {
2
2
  addComment(commentableId: $commentableId, commentableType: $commentableType, body: $body, alignment: $alignment) {
3
- ...CommentData
4
- replies {
5
- id
6
- }
3
+ ...CommentThread
7
4
  }
8
5
  }
@@ -6,6 +6,8 @@ import { I18n } from 'react-i18nify';
6
6
  import classnames from 'classnames';
7
7
 
8
8
  import AddCommentForm from './add_comment_form.component';
9
+ import UpVoteButton from './up_vote_button.component';
10
+ import DownVoteButton from './down_vote_button.component';
9
11
 
10
12
  import commentFragment from './comment.fragment.graphql';
11
13
  import commentDataFragment from './comment_data.fragment.graphql';
@@ -26,8 +28,7 @@ class Comment extends Component {
26
28
 
27
29
  render() {
28
30
  const { comment: { id, author, body, createdAt }, articleClassName } = this.props;
29
-
30
- const formattedCreatedAt = ` ${moment(createdAt, "YYYY-MM-DD HH:mm:ss z").format("LLL")}`;
31
+ const formattedCreatedAt = ` ${moment(createdAt).format("LLL")}`;
31
32
 
32
33
  return (
33
34
  <article id={`comment_${id}`} className={articleClassName}>
@@ -50,10 +51,12 @@ class Comment extends Component {
50
51
  { body }
51
52
  </p>
52
53
  </div>
53
- {this._renderReplies()}
54
54
  <div className="comment__footer">
55
55
  {this._renderReplyButton()}
56
+ {this._renderVoteButtons()}
56
57
  </div>
58
+ {this._renderReplies()}
59
+ {this._renderAdditionalReplyButton()}
57
60
  {this._renderReplyForm()}
58
61
  </article>
59
62
  );
@@ -80,7 +83,55 @@ class Comment extends Component {
80
83
  );
81
84
  }
82
85
 
83
- return <div>&nbsp;</div>;
86
+ return <span>&nbsp;</span>;
87
+ }
88
+
89
+ /**
90
+ * Render additional reply button if user can reply the comment at the bottom of a conversation
91
+ * @private
92
+ * @returns {Void|DOMElement} - Render the reply button or not if user can reply
93
+ */
94
+ _renderAdditionalReplyButton() {
95
+ const { comment: { canHaveReplies, hasReplies }, currentUser, isRootComment } = this.props;
96
+ const { showReplyForm } = this.state;
97
+
98
+ if (currentUser && canHaveReplies) {
99
+ if (hasReplies && isRootComment) {
100
+
101
+ return (
102
+ <div className="comment__additionalreply">
103
+ <button
104
+ className="comment__reply muted-link"
105
+ aria-controls="comment1-reply"
106
+ onClick={() => this.setState({ showReplyForm: !showReplyForm })}
107
+ >
108
+ { I18n.t("components.comment.reply") }
109
+ </button>
110
+ </div>
111
+ );
112
+ }
113
+ }
114
+ return null;
115
+ }
116
+
117
+ /**
118
+ * Render upVote and downVote buttons when the comment is votable
119
+ * @private
120
+ * @returns {Void|DOMElement} - Render the upVote and downVote buttons or not
121
+ */
122
+ _renderVoteButtons() {
123
+ const { comment, votable } = this.props;
124
+
125
+ if (votable) {
126
+ return (
127
+ <div className="comment__votes">
128
+ <UpVoteButton comment={comment} />
129
+ <DownVoteButton comment={comment} />
130
+ </div>
131
+ );
132
+ }
133
+
134
+ return <span>&nbsp;</span>;
84
135
  }
85
136
 
86
137
  /**
@@ -89,7 +140,7 @@ class Comment extends Component {
89
140
  * @returns {Void|DomElement} - A wrapper element with comment replies inside
90
141
  */
91
142
  _renderReplies() {
92
- const { comment: { id, replies }, currentUser, articleClassName } = this.props;
143
+ const { comment: { id, replies }, currentUser, votable, articleClassName } = this.props;
93
144
  let replyArticleClassName = 'comment comment--nested';
94
145
 
95
146
  if (articleClassName === 'comment comment--nested') {
@@ -105,6 +156,7 @@ class Comment extends Component {
105
156
  key={`comment_${id}_reply_${reply.id}`}
106
157
  comment={reply}
107
158
  currentUser={currentUser}
159
+ votable={votable}
108
160
  articleClassName={replyArticleClassName}
109
161
  />
110
162
  ))
@@ -134,6 +186,7 @@ class Comment extends Component {
134
186
  showTitle={false}
135
187
  submitButtonClassName="button small hollow"
136
188
  onCommentAdded={() => this.setState({ showReplyForm: false })}
189
+ autoFocus
137
190
  />
138
191
  );
139
192
  }
@@ -178,14 +231,19 @@ Comment.fragments = {
178
231
  comment: gql`
179
232
  ${commentFragment}
180
233
  ${commentDataFragment}
234
+ ${UpVoteButton.fragments.comment}
235
+ ${DownVoteButton.fragments.comment}
181
236
  `,
182
237
  commentData: gql`
183
238
  ${commentDataFragment}
239
+ ${UpVoteButton.fragments.comment}
240
+ ${DownVoteButton.fragments.comment}
184
241
  `
185
242
  };
186
243
 
187
244
  Comment.defaultProps = {
188
- articleClassName: 'comment'
245
+ articleClassName: 'comment',
246
+ isRootComment: false
189
247
  };
190
248
 
191
249
  Comment.propTypes = {
@@ -196,7 +254,9 @@ Comment.propTypes = {
196
254
  currentUser: PropTypes.shape({
197
255
  name: PropTypes.string.isRequired
198
256
  }),
199
- articleClassName: PropTypes.string.isRequired
257
+ articleClassName: PropTypes.string.isRequired,
258
+ isRootComment: PropTypes.bool,
259
+ votable: PropTypes.bool
200
260
  };
201
261
 
202
262
  export default Comment;
@@ -1,12 +1,17 @@
1
+ /* eslint-disable no-unused-expressions */
1
2
  import { shallow, mount } from 'enzyme';
2
3
  import { filter } from 'graphql-anywhere';
3
4
  import gql from 'graphql-tag';
4
5
 
5
6
  import Comment from './comment.component';
6
7
  import AddCommentForm from './add_comment_form.component';
8
+ import UpVoteButton from './up_vote_button.component';
9
+ import DownVoteButton from './down_vote_button.component';
7
10
 
8
11
  import commentFragment from './comment.fragment.graphql';
9
12
  import commentDataFragment from './comment_data.fragment.graphql';
13
+ import upVoteFragment from './up_vote.fragment.graphql';
14
+ import downVoteFragment from './down_vote.fragment.graphql';
10
15
 
11
16
  import stubComponent from '../support/stub_component';
12
17
  import generateCommentsData from '../support/generate_comments_data';
@@ -17,6 +22,8 @@ describe("<Comment />", () => {
17
22
  let currentUser = null;
18
23
 
19
24
  stubComponent(AddCommentForm);
25
+ stubComponent(UpVoteButton);
26
+ stubComponent(DownVoteButton);
20
27
 
21
28
  beforeEach(() => {
22
29
  let commentsData = generateCommentsData(1);
@@ -26,6 +33,8 @@ describe("<Comment />", () => {
26
33
  const fragment = gql`
27
34
  ${commentFragment}
28
35
  ${commentDataFragment}
36
+ ${upVoteFragment}
37
+ ${downVoteFragment}
29
38
  `;
30
39
 
31
40
  comment = filter(fragment, commentsData[0]);
@@ -79,12 +88,34 @@ describe("<Comment />", () => {
79
88
  expect(wrapper.find('button.comment__reply')).not.to.be.present();
80
89
  });
81
90
 
82
- it("should render comment replies a separate Comment components", () => {
91
+ it("should not render the additional reply button if the parent comment has no replies and isRootcomment", () => {
92
+ comment.canHaveReplies = true;
93
+ comment.hasReplies = false;
94
+ const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} isRootComment />);
95
+ expect(wrapper.find('div.comment__additionalreply')).not.to.be.present();
96
+ });
97
+
98
+ it("should not render the additional reply button if the parent comment has replies and not isRootcomment", () => {
99
+ comment.canHaveReplies = true;
100
+ comment.hasReplies = true;
83
101
  const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} />);
102
+ expect(wrapper.find('div.comment__additionalreply')).not.to.be.present();
103
+ });
104
+
105
+ it("should render the additional reply button if the parent comment has replies and isRootcomment", () => {
106
+ comment.canHaveReplies = true;
107
+ comment.hasReplies = true;
108
+ const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} isRootComment />);
109
+ expect(wrapper.find('div.comment__additionalreply')).to.be.present();
110
+ });
111
+
112
+ it("should render comment replies a separate Comment components", () => {
113
+ const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} votable />);
84
114
  wrapper.find(Comment).forEach((node, idx) => {
85
115
  expect(node).to.have.prop("comment").deep.equal(comment.replies[idx]);
86
116
  expect(node).to.have.prop("currentUser").deep.equal(currentUser);
87
117
  expect(node).to.have.prop("articleClassName").equal("comment comment--nested")
118
+ expect(node).to.have.prop("votable").equal(true);
88
119
  });
89
120
  });
90
121
 
@@ -100,6 +131,11 @@ describe("<Comment />", () => {
100
131
  expect(wrapper).to.have.prop("articleClassName").equal("comment");
101
132
  });
102
133
 
134
+ it("should have a default prop isRootComment with value false", () => {
135
+ const wrapper = mount(<Comment comment={comment} currentUser={currentUser} />);
136
+ expect(wrapper).to.have.prop("isRootComment").equal(false);
137
+ });
138
+
103
139
  describe("when user is not logged in", () => {
104
140
  beforeEach(() => {
105
141
  currentUser = null;
@@ -122,4 +158,16 @@ describe("<Comment />", () => {
122
158
  const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} />);
123
159
  expect(wrapper.find('span.alert.label')).to.have.text('Against');
124
160
  });
161
+
162
+ describe("when the comment is votable", () => {
163
+ it("should render an UpVoteButton component", () => {
164
+ const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} votable />);
165
+ expect(wrapper.find(UpVoteButton)).to.have.prop("comment").deep.equal(comment);
166
+ })
167
+
168
+ it("should render an DownVoteButton component", () => {
169
+ const wrapper = shallow(<Comment comment={comment} currentUser={currentUser} votable />);
170
+ expect(wrapper.find(DownVoteButton)).to.have.prop("comment").deep.equal(comment);
171
+ })
172
+ });
125
173
  });
@@ -6,6 +6,9 @@ fragment CommentData on Comment {
6
6
  name,
7
7
  avatarUrl
8
8
  }
9
+ hasReplies
9
10
  canHaveReplies
10
11
  alignment
12
+ ...UpVote
13
+ ...DownVote
11
14
  }
@@ -1,4 +1,4 @@
1
- import { Component } from 'react';
1
+ import { Component, PropTypes } from 'react';
2
2
  import { I18n } from 'react-i18nify';
3
3
 
4
4
  /**
@@ -7,22 +7,67 @@ import { I18n } from 'react-i18nify';
7
7
  * @augments Component
8
8
  * @todo Needs a proper implementation
9
9
  */
10
- export default class CommentOrderSelector extends Component {
10
+ class CommentOrderSelector extends Component {
11
+
12
+ constructor(props) {
13
+ super(props);
14
+ this.state = {
15
+ orderBy: this.props.defaultOrderBy
16
+ }
17
+ }
18
+
19
+ componentDidMount() {
20
+ $(document).foundation();
21
+ }
22
+
11
23
  render() {
24
+ const { orderBy } = this.state;
25
+
12
26
  return (
13
27
  <div className="order-by__dropdown order-by__dropdown--right">
14
28
  <span className="order-by__text">{ I18n.t("components.comment_order_selector.title") }</span>
15
29
  <ul className="dropdown menu" data-dropdown-menu>
16
30
  <li>
17
- <a>{ I18n.t("components.comment_order_selector.order.most_voted") }</a>
31
+ <a>{ I18n.t(`components.comment_order_selector.${orderBy}`) }</a>
18
32
  <ul className="menu">
19
- <li><a>{ I18n.t("components.comment_order_selector.order.most_voted") }</a></li>
20
- <li><a>{ I18n.t("components.comment_order_selector.order.recent") }</a></li>
21
- <li><a>{ I18n.t("components.comment_order_selector.order.older") }</a></li>
33
+ <li>
34
+ <a href="" className="test" onClick={(event) => this._updateOrder(event, "best_rated")} >
35
+ { I18n.t("components.comment_order_selector.order.best_rated") }
36
+ </a>
37
+ </li>
38
+ <li>
39
+ <a href="" onClick={(event) => this._updateOrder(event, "recent")} >
40
+ { I18n.t("components.comment_order_selector.order.recent") }
41
+ </a>
42
+ </li>
43
+ <li>
44
+ <a href="" onClick={(event) => this._updateOrder(event, "older")} >
45
+ { I18n.t("components.comment_order_selector.order.older") }
46
+ </a>
47
+ </li>
48
+ <li>
49
+ <a href="" onClick={(event) => this._updateOrder(event, "most_discussed")} >
50
+ { I18n.t("components.comment_order_selector.order.most_discussed") }
51
+ </a>
52
+ </li>
22
53
  </ul>
23
54
  </li>
24
55
  </ul>
25
56
  </div>
26
57
  );
27
58
  }
59
+
60
+ _updateOrder(event, orderBy) {
61
+ event.preventDefault();
62
+ this.setState({ orderBy });
63
+ this.props.reorderComments(orderBy);
64
+ }
65
+
28
66
  }
67
+
68
+ CommentOrderSelector.propTypes = {
69
+ reorderComments: PropTypes.func.isRequired,
70
+ defaultOrderBy: PropTypes.string.isRequired
71
+ };
72
+
73
+ export default CommentOrderSelector;
@@ -2,8 +2,19 @@ import { shallow } from 'enzyme';
2
2
  import CommentOrderSelector from './comment_order_selector.component';
3
3
 
4
4
  describe('<CommentOrderSelector />', () => {
5
+ const orderBy = "older";
6
+ const reorderComments = sinon.spy();
7
+
5
8
  it("renders a div with classes order-by__dropdown order-by__dropdown--right", () => {
6
- const wrapper = shallow(<CommentOrderSelector />);
9
+ const wrapper = shallow(<CommentOrderSelector reorderComments={reorderComments} defaultOrderBy={orderBy} />);
7
10
  expect(wrapper.find('div.order-by__dropdown.order-by__dropdown--right')).to.present();
8
11
  })
12
+
13
+ it("should set state order to best_rated if user clicks on the first element", () => {
14
+ const preventDefault = sinon.spy();
15
+ const wrapper = shallow(<CommentOrderSelector reorderComments={reorderComments} defaultOrderBy={orderBy} />);
16
+ wrapper.find('a.test').simulate('click', {preventDefault});
17
+ expect(reorderComments).to.calledWith("best_rated");
18
+ });
9
19
  })
20
+
@@ -15,13 +15,18 @@ import commentThreadFragment from './comment_thread.fragment.graphql'
15
15
  */
16
16
  class CommentThread extends Component {
17
17
  render() {
18
- const { comment, currentUser } = this.props;
18
+ const { comment, currentUser, votable } = this.props;
19
19
 
20
20
  return (
21
21
  <div>
22
22
  {this._renderTitle()}
23
23
  <div className="comment-thread">
24
- <Comment comment={filter(Comment.fragments.comment, comment)} currentUser={currentUser} />
24
+ <Comment
25
+ comment={filter(Comment.fragments.comment, comment)}
26
+ currentUser={currentUser}
27
+ votable={votable}
28
+ isRootComment
29
+ />
25
30
  </div>
26
31
  </div>
27
32
  );
@@ -33,9 +38,9 @@ class CommentThread extends Component {
33
38
  * @returns {Void|DOMElement} - The conversation's title
34
39
  */
35
40
  _renderTitle() {
36
- const { comment: { author, replies } } = this.props;
41
+ const { comment: { author, hasReplies } } = this.props;
37
42
 
38
- if (replies.length > 0) {
43
+ if (hasReplies) {
39
44
  return (
40
45
  <h6 className="comment-thread__title">
41
46
  { I18n.t("components.comment_thread.title", { authorName: author.name }) }
@@ -58,7 +63,8 @@ CommentThread.propTypes = {
58
63
  currentUser: PropTypes.shape({
59
64
  name: PropTypes.string.isRequired
60
65
  }),
61
- comment: propType(CommentThread.fragments.comment).isRequired
66
+ comment: propType(CommentThread.fragments.comment).isRequired,
67
+ votable: PropTypes.bool
62
68
  };
63
69
 
64
70
  export default CommentThread;
@@ -48,7 +48,7 @@ describe('<CommentThread />', () => {
48
48
 
49
49
  describe("when comment does have replies", () => {
50
50
  beforeEach(() => {
51
- comment.replies = generateCommentsData(3);
51
+ comment.hasReplies = true;
52
52
  });
53
53
 
54
54
  it("should render a h6 comment-thread__title with author name", () => {
@@ -66,6 +66,16 @@ describe('<CommentThread />', () => {
66
66
  it("and pass filter comment data as a prop to it", () => {
67
67
  const wrapper = shallow(<CommentThread comment={comment} currentUser={currentUser} />);
68
68
  expect(wrapper.find(Comment).first()).to.have.prop("comment").deep.equal(filter(commentFragment, comment));
69
- });
70
- });
69
+ });
70
+
71
+ it("and pass the votable as a prop to it", () => {
72
+ const wrapper = shallow(<CommentThread comment={comment} currentUser={currentUser} votable />);
73
+ expect(wrapper.find(Comment).first()).to.have.prop("votable").equal(true);
74
+ });
75
+
76
+ it("and pass the isRootComment equal true", () => {
77
+ const wrapper = shallow(<CommentThread comment={comment} currentUser={currentUser} votable isRootComment />);
78
+ expect(wrapper.find(Comment).first()).to.have.prop("isRootComment").equal(true);
79
+ });
80
+ });
71
81
  });
@@ -2,8 +2,6 @@ fragment CommentThread on Comment {
2
2
  author {
3
3
  name
4
4
  }
5
- replies {
6
- id
7
- }
5
+ hasReplies,
8
6
  ...Comment
9
7
  }
@@ -8,6 +8,7 @@ import Application from '../application/application.component';
8
8
 
9
9
  import CommentThread from './comment_thread.component';
10
10
  import AddCommentForm from './add_comment_form.component';
11
+ import CommentOrderSelector from './comment_order_selector.component';
11
12
 
12
13
  import commentsQuery from './comments.query.graphql';
13
14
 
@@ -20,15 +21,26 @@ import commentsQuery from './comments.query.graphql';
20
21
  */
21
22
  export class Comments extends Component {
22
23
  render() {
23
- const { comments } = this.props;
24
+ const { comments, reorderComments, orderBy, loading } = this.props;
25
+ let commentClasses = "comments";
26
+ let commentHeader = I18n.t("components.comments.title", { count: comments.length });
27
+
28
+ if (loading) {
29
+ commentClasses += " loading-comments"
30
+ commentHeader = I18n.t("components.comments.loading");
31
+ }
24
32
 
25
33
  return (
26
34
  <div className="columns large-9" id="comments">
27
- <section className="comments">
35
+ <section className={commentClasses}>
28
36
  <div className="row collapse order-by">
29
37
  <h2 className="order-by__text section-heading">
30
- { I18n.t("components.comments.title", { count: comments.length }) }
38
+ { commentHeader }
31
39
  </h2>
40
+ <CommentOrderSelector
41
+ reorderComments={reorderComments}
42
+ defaultOrderBy={orderBy}
43
+ />
32
44
  </div>
33
45
  {this._renderCommentThreads()}
34
46
  {this._renderAddCommentForm()}
@@ -36,24 +48,25 @@ export class Comments extends Component {
36
48
  </div>
37
49
  );
38
50
  }
39
-
51
+
40
52
  /**
41
53
  * Iterates the comment's collection and render a CommentThread for each one
42
54
  * @private
43
55
  * @returns {ReactComponent[]} - A collection of CommentThread components
44
56
  */
45
57
  _renderCommentThreads() {
46
- const { comments, currentUser } = this.props;
58
+ const { comments, currentUser, options: { votable } } = this.props;
47
59
 
48
60
  return comments.map((comment) => (
49
61
  <CommentThread
50
62
  key={comment.id}
51
63
  comment={filter(CommentThread.fragments.comment, comment)}
52
64
  currentUser={currentUser}
65
+ votable={votable}
53
66
  />
54
67
  ))
55
68
  }
56
-
69
+
57
70
  /**
58
71
  * If current user is present it renders the add comment form
59
72
  * @private
@@ -61,7 +74,7 @@ export class Comments extends Component {
61
74
  */
62
75
  _renderAddCommentForm() {
63
76
  const { currentUser, commentableId, commentableType, options: { arguable } } = this.props;
64
-
77
+
65
78
  if (currentUser) {
66
79
  return (
67
80
  <AddCommentForm
@@ -78,6 +91,7 @@ export class Comments extends Component {
78
91
  }
79
92
 
80
93
  Comments.propTypes = {
94
+ loading: PropTypes.bool,
81
95
  comments: PropTypes.arrayOf(PropTypes.shape({
82
96
  id: PropTypes.string.isRequired
83
97
  })),
@@ -88,7 +102,9 @@ Comments.propTypes = {
88
102
  commentableType: PropTypes.string.isRequired,
89
103
  options: PropTypes.shape({
90
104
  arguable: PropTypes.bool
91
- }).isRequired
105
+ }).isRequired,
106
+ orderBy: PropTypes.string.isRequired,
107
+ reorderComments: PropTypes.func.isRequired
92
108
  };
93
109
 
94
110
  /**
@@ -99,13 +115,22 @@ const CommentsWithData = graphql(gql`
99
115
  ${commentsQuery}
100
116
  ${CommentThread.fragments.comment}
101
117
  `, {
102
- options: { pollInterval: 15000 },
103
- props: ({ ownProps, data: { currentUser, comments }}) => ({
118
+ options: {
119
+ pollInterval: 15000
120
+ },
121
+ props: ({ ownProps, data: {loading, currentUser, comments, refetch }}) => ({
122
+ loading: loading,
104
123
  comments: comments || [],
105
124
  currentUser: currentUser || null,
106
125
  commentableId: ownProps.commentableId,
107
126
  commentableType: ownProps.commentableType,
108
- options: ownProps.options
127
+ orderBy: ownProps.orderBy,
128
+ options: ownProps.options,
129
+ reorderComments: (orderBy) => {
130
+ return refetch({
131
+ orderBy
132
+ });
133
+ }
109
134
  })
110
135
  })(Comments);
111
136
 
@@ -120,6 +145,7 @@ const CommentsApplication = ({ locale, commentableId, commentableType, options }
120
145
  commentableId={commentableId}
121
146
  commentableType={commentableType}
122
147
  options={options}
148
+ orderBy="older"
123
149
  />
124
150
  </Application>
125
151
  );