pageflow 17.1.0 → 17.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +319 -345
  3. data/README.md +3 -4
  4. data/admins/pageflow/accounts.rb +6 -6
  5. data/admins/pageflow/entry.rb +10 -8
  6. data/admins/pageflow/membership.rb +11 -11
  7. data/admins/pageflow/translations.rb +5 -5
  8. data/app/assets/images/pageflow/admin/icons/comment.svg +1 -0
  9. data/app/assets/javascripts/pageflow/dist/ui.js +1350 -630
  10. data/app/assets/javascripts/pageflow/editor/vendor.js +0 -1
  11. data/app/assets/javascripts/pageflow/ui.js +0 -1
  12. data/app/assets/stylesheets/pageflow/admin/entry_comments_indicator.scss +45 -0
  13. data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +8 -1
  14. data/app/assets/stylesheets/pageflow/admin.scss +1 -0
  15. data/app/assets/stylesheets/pageflow/animations/spin.scss +9 -0
  16. data/app/assets/stylesheets/pageflow/animations.scss +1 -0
  17. data/app/assets/stylesheets/pageflow/editor/background_positioning.scss +21 -5
  18. data/app/assets/stylesheets/pageflow/editor/base.scss +9 -1
  19. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +13 -1
  20. data/app/assets/stylesheets/pageflow/editor/edit_configuration_view.scss +5 -0
  21. data/app/assets/stylesheets/pageflow/editor/file_folders.scss +127 -0
  22. data/app/assets/stylesheets/pageflow/editor/file_meta_data.scss +0 -1
  23. data/app/assets/stylesheets/pageflow/editor/file_meta_data_overlay.scss +45 -0
  24. data/app/assets/stylesheets/pageflow/editor/file_preview.scss +138 -0
  25. data/app/assets/stylesheets/pageflow/editor/file_references.scss +68 -0
  26. data/app/assets/stylesheets/pageflow/editor/file_settings_dialog.scss +1 -1
  27. data/app/assets/stylesheets/pageflow/editor/file_stage_icons.scss +17 -0
  28. data/app/assets/stylesheets/pageflow/editor/file_stages.scss +25 -32
  29. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +31 -48
  30. data/app/assets/stylesheets/pageflow/editor/file_type_pills.scss +73 -0
  31. data/app/assets/stylesheets/pageflow/editor/files.scss +230 -50
  32. data/app/assets/stylesheets/pageflow/editor/filtered_files.scss +142 -14
  33. data/app/assets/stylesheets/pageflow/editor/folder_breadcrumb.scss +40 -0
  34. data/app/assets/stylesheets/pageflow/editor/info_box.scss +12 -0
  35. data/app/assets/stylesheets/pageflow/editor/inputs/edit_defaults_button.scss +15 -0
  36. data/app/assets/stylesheets/pageflow/editor/inputs.scss +1 -0
  37. data/app/assets/stylesheets/pageflow/editor/list.scss +88 -38
  38. data/app/assets/stylesheets/pageflow/editor/manage_files.scss +9 -0
  39. data/app/assets/stylesheets/pageflow/editor/menu.scss +14 -0
  40. data/app/assets/stylesheets/pageflow/editor/move_to_folder_dialog.scss +83 -0
  41. data/app/assets/stylesheets/pageflow/mixins/pageflow.scss +9 -5
  42. data/app/assets/stylesheets/pageflow/ui/color_picker.scss +230 -0
  43. data/app/assets/stylesheets/pageflow/ui/forms.scss +34 -4
  44. data/app/assets/stylesheets/pageflow/ui/functions.scss +12 -2
  45. data/app/assets/stylesheets/pageflow/ui/input/color_input.scss +9 -16
  46. data/app/assets/stylesheets/pageflow/ui/input/text_area_input.scss +15 -0
  47. data/app/assets/stylesheets/pageflow/ui/overrides.scss +8 -0
  48. data/app/assets/stylesheets/pageflow/ui/properties.scss +29 -0
  49. data/app/assets/stylesheets/pageflow/ui/tabs_view.scss +8 -3
  50. data/app/assets/stylesheets/pageflow/ui.scss +4 -2
  51. data/app/controllers/pageflow/editor/entries_controller.rb +1 -0
  52. data/app/controllers/pageflow/editor/file_folders_controller.rb +80 -0
  53. data/app/controllers/pageflow/editor/file_import_controller.rb +1 -0
  54. data/app/controllers/pageflow/editor/files_controller.rb +15 -6
  55. data/app/controllers/pageflow/editor/oembeds_controller.rb +21 -0
  56. data/app/controllers/pageflow/entries_controller.rb +17 -13
  57. data/app/controllers/pageflow/review/comment_thread_reads_controller.rb +30 -0
  58. data/app/controllers/pageflow/review/comment_threads_controller.rb +60 -0
  59. data/app/controllers/pageflow/review/comments_controller.rb +53 -0
  60. data/app/controllers/pageflow/revisions_controller.rb +4 -1
  61. data/app/helpers/pageflow/admin/entries_helper.rb +40 -0
  62. data/app/helpers/pageflow/admin/widgets_helper.rb +2 -2
  63. data/app/helpers/pageflow/common_entry_seed_helper.rb +5 -3
  64. data/app/helpers/pageflow/editor/config_helper.rb +3 -1
  65. data/app/helpers/pageflow/entries_helper.rb +24 -42
  66. data/app/helpers/pageflow/entry_json_seed_helper.rb +4 -4
  67. data/app/helpers/pageflow/public_i18n_helper.rb +9 -8
  68. data/app/helpers/pageflow/structured_data_helper.rb +4 -1
  69. data/app/helpers/pageflow/themes_helper.rb +1 -3
  70. data/app/helpers/pageflow/widgets_helper.rb +2 -1
  71. data/app/inputs/pageflow_permalink_input.rb +6 -2
  72. data/app/models/concerns/pageflow/auto_generated_perma_id.rb +11 -4
  73. data/app/models/concerns/pageflow/reusable_file.rb +1 -1
  74. data/app/models/concerns/pageflow/serialization_blacklist.rb +2 -4
  75. data/app/models/concerns/pageflow/translated_attributes.rb +101 -0
  76. data/app/models/concerns/pageflow/uploadable_file.rb +1 -1
  77. data/app/models/pageflow/comment.rb +30 -0
  78. data/app/models/pageflow/comment_thread.rb +65 -0
  79. data/app/models/pageflow/comment_thread_read.rb +22 -0
  80. data/app/models/pageflow/customized_theme.rb +3 -2
  81. data/app/models/pageflow/draft_entry.rb +20 -8
  82. data/app/models/pageflow/entry.rb +2 -0
  83. data/app/models/pageflow/entry_at_revision.rb +9 -1
  84. data/app/models/pageflow/entry_comment_summary.rb +114 -0
  85. data/app/models/pageflow/file_folder.rb +74 -0
  86. data/app/models/pageflow/file_reuse.rb +3 -2
  87. data/app/models/pageflow/file_usage.rb +8 -0
  88. data/app/models/pageflow/image_file.rb +24 -20
  89. data/app/models/pageflow/image_file_url_templates.rb +3 -3
  90. data/app/models/pageflow/legal_info.rb +38 -0
  91. data/app/models/pageflow/nested_revision_component_copy.rb +1 -1
  92. data/app/models/pageflow/permalink.rb +1 -0
  93. data/app/models/pageflow/revision.rb +6 -2
  94. data/app/models/pageflow/site.rb +10 -0
  95. data/app/models/pageflow/used_file.rb +8 -2
  96. data/app/models/pageflow/widget.rb +2 -2
  97. data/app/views/pageflow/audio_files/_audio_file.json.jbuilder +0 -1
  98. data/app/views/pageflow/editor/config/_seeds.json.jbuilder +4 -2
  99. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +2 -1
  100. data/app/views/pageflow/editor/entries/seed.json.erb +1 -0
  101. data/app/views/pageflow/editor/file_folders/_file_folder.json.jbuilder +5 -0
  102. data/app/views/pageflow/editor/file_folders/create.json.jbuilder +1 -0
  103. data/app/views/pageflow/editor/file_folders/index.json.jbuilder +3 -0
  104. data/app/views/pageflow/editor/files/_file.json.jbuilder +2 -1
  105. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +3 -0
  106. data/app/views/pageflow/editor/video_files/_video_file.json.jbuilder +3 -0
  107. data/app/views/pageflow/files/_file.json.jbuilder +2 -0
  108. data/app/views/pageflow/image_files/_image_file.json.jbuilder +0 -1
  109. data/app/views/pageflow/review/comment_threads/_comment_thread.json.jbuilder +20 -0
  110. data/app/views/pageflow/review/comment_threads/create.json.jbuilder +2 -0
  111. data/app/views/pageflow/review/comment_threads/index.json.jbuilder +13 -0
  112. data/app/views/pageflow/review/comments/_comment.json.jbuilder +13 -0
  113. data/app/views/pageflow/review/comments/create.json.jbuilder +1 -0
  114. data/app/views/pageflow/structured_data/_entry.json.jbuilder +2 -3
  115. data/app/views/pageflow/video_files/_video_file.json.jbuilder +0 -1
  116. data/config/locales/de.yml +152 -14
  117. data/config/locales/en.yml +150 -14
  118. data/config/routes.rb +14 -0
  119. data/db/migrate/20140418225525_setup_schema.rb +2 -2
  120. data/db/migrate/20251015000000_add_structured_data_type_name_to_revisions.rb +5 -0
  121. data/db/migrate/20251029142849_convert_legacy_social_embeds_to_unified_social_embed.rb +38 -0
  122. data/db/migrate/20251119083347_fix_main_storyline_positions.rb +16 -0
  123. data/db/migrate/20251119083348_ensure_scrolled_entries_have_excursion_storyline.rb +15 -0
  124. data/db/migrate/20260303000000_add_layout_version_to_revisions.rb +6 -0
  125. data/db/migrate/20260323000000_create_comment_threads_and_comments.rb +30 -0
  126. data/db/migrate/20260414000000_add_subject_range_to_comment_threads.rb +5 -0
  127. data/db/migrate/20260415000000_add_section_perma_id_to_comment_threads.rb +5 -0
  128. data/db/migrate/20260727000000_add_quote_to_comments.rb +5 -0
  129. data/db/migrate/20260728000000_create_file_folders.rb +17 -0
  130. data/db/migrate/20260805000000_add_attribute_translations_to_sites.rb +5 -0
  131. data/db/migrate/20260806000000_add_edited_at_to_comments.rb +5 -0
  132. data/db/migrate/20260810000000_create_pageflow_scrolled_lottie_files.rb +24 -0
  133. data/db/migrate/20260817000000_create_comment_thread_reads.rb +16 -0
  134. data/db/migrate/20260819000000_add_unread_comments_since_at_to_users.rb +18 -0
  135. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +8665 -3890
  136. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +979 -3571
  137. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-client.js +20199 -28120
  138. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/react-server.js +18652 -26584
  139. data/entry_types/scrolled/app/assets/stylesheets/pageflow_scrolled/ui.scss +2 -0
  140. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +33 -3
  141. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -3
  142. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +21 -1
  143. data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +3 -3
  144. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +7 -5
  145. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +5 -2
  146. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +13 -5
  147. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +28 -13
  148. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +26 -11
  149. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +2 -2
  150. data/entry_types/scrolled/app/helpers/pageflow_scrolled/sprockets_helper.rb +16 -0
  151. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +174 -3
  152. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +49 -7
  153. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file.rb +6 -0
  154. data/entry_types/scrolled/app/models/pageflow_scrolled/lottie_file_url_templates.rb +16 -0
  155. data/entry_types/scrolled/app/models/pageflow_scrolled/storyline.rb +1 -0
  156. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +13 -12
  157. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +30 -10
  158. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +9 -0
  159. data/entry_types/scrolled/app/views/pageflow_scrolled/favicons/_entry.html.erb +1 -1
  160. data/entry_types/scrolled/config/configuration_schemas/pageflow-scrolled.json +414 -0
  161. data/entry_types/scrolled/config/locales/de.yml +512 -65
  162. data/entry_types/scrolled/config/locales/en.yml +518 -52
  163. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +2 -2
  164. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +51 -6
  165. data/entry_types/scrolled/lib/pageflow_scrolled/configuration_schemas.rb +91 -0
  166. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +2 -1
  167. data/entry_types/scrolled/lib/pageflow_scrolled/entry_file_reference_locations.rb +71 -0
  168. data/entry_types/scrolled/lib/pageflow_scrolled/entry_structured_data_types/faq_page.rb +58 -0
  169. data/entry_types/scrolled/lib/pageflow_scrolled/file_reference_locations.rb +69 -0
  170. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +205 -22
  171. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +2 -4
  172. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +56 -36
  173. data/entry_types/scrolled/lib/pageflow_scrolled/theme_options_default_scale.rb +35 -0
  174. data/entry_types/scrolled/lib/pageflow_scrolled.rb +13 -0
  175. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +19 -1
  176. data/entry_types/scrolled/package/config/configurationSchemas.js +70 -0
  177. data/entry_types/scrolled/package/config/rollup/configurationSchemas.js +19 -0
  178. data/entry_types/scrolled/package/config/webpack.js +72 -0
  179. data/entry_types/scrolled/package/contentElements/hotspots-frontend.css +1 -1
  180. data/entry_types/scrolled/package/contentElements/hotspots-frontend.js +1181 -915
  181. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.css +1 -0
  182. data/entry_types/scrolled/package/contentElements/inlineBeforeAfter-frontend.js +219 -0
  183. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.css +1 -0
  184. data/entry_types/scrolled/package/contentElements/lottieAnimation-frontend.js +244 -0
  185. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.css +1 -0
  186. data/entry_types/scrolled/package/contentElements/socialEmbed-frontend.js +823 -0
  187. data/entry_types/scrolled/package/contentElements/tikTokEmbed-frontend.js +71 -21
  188. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.css +1 -0
  189. data/entry_types/scrolled/package/contentElements/twitterEmbed-frontend.js +277 -0
  190. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.css +1 -0
  191. data/entry_types/scrolled/package/contentElements/videoEmbed-frontend.js +244 -0
  192. data/entry_types/scrolled/package/contentElements-editor.js +1915 -1097
  193. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  194. data/entry_types/scrolled/package/contentElements-frontend.js +3093 -1679
  195. data/entry_types/scrolled/package/editor.css +1 -0
  196. data/entry_types/scrolled/package/editor.js +8667 -4077
  197. data/entry_types/scrolled/package/entryState.js +1600 -0
  198. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-20c600de.js +1979 -0
  199. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-58189220.js +2538 -0
  200. data/entry_types/scrolled/package/frontend/{PhonePlatformContext-9f76033e.js → PhonePlatformContext-035a99fa.js} +7 -12
  201. data/entry_types/scrolled/package/frontend/PhonePlatformContext-9da43797.js +33 -0
  202. data/entry_types/scrolled/package/frontend/Placeholder.module-bf0966b4.js +5267 -0
  203. data/entry_types/scrolled/package/frontend/Placeholder.module-d22a9335.js +4180 -0
  204. data/entry_types/scrolled/package/frontend/ThemeIcon-ab834849.js +754 -0
  205. data/entry_types/scrolled/package/frontend/ThemeIcon-f6cb3a8f.js +773 -0
  206. data/entry_types/scrolled/package/frontend/{ToggleFullscreenCornerButton-788e9cdb.js → ToggleFullscreenCornerButton-30fd1124.js} +6 -6
  207. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-61c25224.js +72 -0
  208. data/entry_types/scrolled/package/frontend/Viewer-1074fd59.js +147 -0
  209. data/entry_types/scrolled/package/frontend/Viewer-1482ca34.js +480 -0
  210. data/entry_types/scrolled/package/frontend/Viewer-70504231.js +210 -0
  211. data/entry_types/scrolled/package/frontend/{Viewer-0345ce57.js → Viewer-cc8d4072.js} +84 -92
  212. data/entry_types/scrolled/package/frontend/Wavesurfer-656e3c36.js +302 -0
  213. data/entry_types/scrolled/package/frontend/Wavesurfer-b753b838.js +385 -0
  214. data/entry_types/scrolled/package/frontend/commenting.css +1 -0
  215. data/entry_types/scrolled/package/frontend/extensions-167ae143.js +1455 -0
  216. data/entry_types/scrolled/package/frontend/extensions-2318f92b.js +5918 -0
  217. data/entry_types/scrolled/package/frontend/extensions-a461fd13.js +4890 -0
  218. data/entry_types/scrolled/package/frontend/extensions-c98269fd.js +1982 -0
  219. data/entry_types/scrolled/package/frontend/i18n-493cd2a6.js +93 -0
  220. data/entry_types/scrolled/package/frontend/i18n-e06cac14.js +100 -0
  221. data/entry_types/scrolled/package/frontend/{index-eb670c2f.js → index-2e5546f7.js} +36 -44
  222. data/entry_types/scrolled/package/frontend/index-de2b418d.js +130 -0
  223. data/entry_types/scrolled/package/frontend/index.css +1 -1
  224. data/entry_types/scrolled/package/frontend/index.js +1870 -875
  225. data/entry_types/scrolled/package/frontend/inlineEditing.css +1 -0
  226. data/entry_types/scrolled/package/frontend/useContentElementEditorState-a084912e.js +25 -0
  227. data/entry_types/scrolled/package/frontend/useDelayedBoolean-a387d85b.js +24 -0
  228. data/entry_types/scrolled/package/frontend/{usePhonePlatform-c2ba875d.js → usePhonePlatform-4ecb96d4.js} +1 -1
  229. data/entry_types/scrolled/package/frontend/usePhonePlatform-ce9ff08d.js +8 -0
  230. data/entry_types/scrolled/package/frontend-server.js +20 -209
  231. data/entry_types/scrolled/package/package.json +5 -3
  232. data/entry_types/scrolled/package/review.css +1 -0
  233. data/entry_types/scrolled/package/review.js +3306 -0
  234. data/entry_types/scrolled/package/testHelpers.js +836 -359
  235. data/entry_types/scrolled/package/widgets/consentBar.css +1 -1
  236. data/entry_types/scrolled/package/widgets/consentBar.js +269 -290
  237. data/entry_types/scrolled/package/widgets/defaultNavigation.css +2 -2
  238. data/entry_types/scrolled/package/widgets/defaultNavigation.js +911 -352
  239. data/entry_types/scrolled/package/widgets/excursionSheet.css +1 -1
  240. data/entry_types/scrolled/package/widgets/excursionSheet.js +87 -124
  241. data/entry_types/scrolled/package/widgets/iconInlineFileRights.css +1 -1
  242. data/entry_types/scrolled/package/widgets/iconInlineFileRights.js +62 -29
  243. data/entry_types/scrolled/package/widgets/iconScrollIndicator.js +32 -13
  244. data/entry_types/scrolled/package/widgets/mainStorylineSheet.css +1 -1
  245. data/entry_types/scrolled/package/widgets/mainStorylineSheet.js +56 -100
  246. data/entry_types/scrolled/package/widgets/textInlineFileRights.css +1 -1
  247. data/entry_types/scrolled/package/widgets/textInlineFileRights.js +33 -28
  248. data/entry_types/scrolled/package/widgets-server.js +1 -0
  249. data/entry_types/scrolled/spec/factories/lottie_files.rb +29 -0
  250. data/entry_types/scrolled/spec/fixtures/animation.lottie +0 -0
  251. data/entry_types/scrolled/spec/fixtures/font.woff +0 -0
  252. data/entry_types/scrolled/spec/fixtures/font.woff2 +0 -0
  253. data/lib/generators/pageflow/resque/resque_generator.rb +0 -2
  254. data/lib/pageflow/configuration.rb +49 -7
  255. data/lib/pageflow/deprecation.rb +19 -0
  256. data/lib/pageflow/engine.rb +1 -1
  257. data/lib/pageflow/entries_controller_env_helper.rb +32 -2
  258. data/lib/pageflow/entry_export_import/entry_serialization.rb +4 -4
  259. data/lib/pageflow/entry_export_import/page_type_versions.rb +2 -2
  260. data/lib/pageflow/entry_export_import/revision_serialization/import.rb +10 -0
  261. data/lib/pageflow/entry_export_import/revision_serialization.rb +3 -0
  262. data/lib/pageflow/entry_structured_data_types.rb +43 -0
  263. data/lib/pageflow/entry_type_configuration.rb +1 -0
  264. data/lib/pageflow/file_type.rb +2 -2
  265. data/lib/pageflow/file_types.rb +1 -1
  266. data/lib/pageflow/oembed_providers.rb +42 -0
  267. data/lib/pageflow/primary_domain_entry_redirect.rb +6 -0
  268. data/lib/pageflow/rails_version.rb +13 -2
  269. data/lib/pageflow/themes.rb +41 -0
  270. data/lib/pageflow/user_mixin.rb +12 -0
  271. data/lib/pageflow/version.rb +1 -1
  272. data/lib/pageflow.rb +1 -0
  273. data/package/config/eslint-rules/documented-in-toc.js +125 -0
  274. data/package/config/jest/index.js +0 -1
  275. data/package/config/webpack.js +0 -1
  276. data/package/config/webpack5.js +0 -1
  277. data/package/editor.js +4378 -1897
  278. data/package/frontend.js +647 -886
  279. data/package/package.json +2 -1
  280. data/package/review.js +384 -0
  281. data/package/testHelpers.js +248 -188
  282. data/package/ui.js +1346 -630
  283. data/package/vendor/stubs/wysihtml5.js +2 -0
  284. data/spec/factories/comment_thread_reads.rb +10 -0
  285. data/spec/factories/comment_threads.rb +10 -0
  286. data/spec/factories/comments.rb +9 -0
  287. data/spec/factories/file_folders.rb +8 -0
  288. data/spec/factories/published_entries.rb +2 -0
  289. metadata +188 -67
  290. data/app/assets/stylesheets/pageflow/editor/select_button.scss +0 -51
  291. data/entry_types/scrolled/app/helpers/pageflow_scrolled/generated_media_queries_helper.rb +0 -55
  292. data/entry_types/scrolled/package/frontend/FloatingPortalRootProvider-51914be7.js +0 -5439
  293. data/entry_types/scrolled/package/frontend/ThemeIcon-81f2f066.js +0 -1932
  294. data/entry_types/scrolled/package/frontend/Viewer-cdc549cc.js +0 -147
  295. data/entry_types/scrolled/package/frontend/Wavesurfer-1cdc3925.js +0 -313
  296. data/entry_types/scrolled/package/frontend/components-96660ffd.js +0 -3803
  297. data/entry_types/scrolled/package/frontend/inherits-539844a6.js +0 -99
  298. data/entry_types/scrolled/package/frontend/useContentElementEditorState-77fe6c79.js +0 -51
  299. data/entry_types/scrolled/package/widgets/excursionDialog.css +0 -1
  300. data/entry_types/scrolled/package/widgets/excursionDialog.js +0 -109
  301. data/lib/generators/pageflow/resque/templates/resque_enqueue_after_commit_patch.rb +0 -25
  302. data/package/vendor/jquery.minicolors.js +0 -1108
@@ -183,6 +183,7 @@ en:
183
183
  author: Author
184
184
  created_at: Created
185
185
  credits: Credits
186
+ structured_data_type_name: Structured data type
186
187
  edited_at: Edited
187
188
  embed_code: Embed
188
189
  first_published_at: First published at
@@ -375,6 +376,11 @@ en:
375
376
  attributes:
376
377
  user:
377
378
  required: User must be selected
379
+ pageflow/site:
380
+ attributes:
381
+ attribute_translations:
382
+ not_translatable: contains an attribute that cannot be translated
383
+ unknown_locale: contains an unknown locale
378
384
  models:
379
385
  account:
380
386
  one: Account
@@ -821,6 +827,20 @@ en:
821
827
  site_defaults_inline_help: The following settings will be used as defaults for new stories in this account. Changes do not affect existing stories.
822
828
  entries:
823
829
  add_folder: Add folder
830
+ comments:
831
+ tooltip: "Comments: %{summary}"
832
+ topic_count:
833
+ one: 1 unresolved topic
834
+ other: "%{count} unresolved topics"
835
+ unread_reply_count:
836
+ one: 1 unread reply
837
+ other: "%{count} unread replies"
838
+ unread_resolution_count:
839
+ one: 1 newly resolved topic
840
+ other: "%{count} newly resolved topics"
841
+ unread_topic_count:
842
+ one: 1 unread topic
843
+ other: "%{count} unread topics"
824
844
  confirm_depublish: Depublish this story?
825
845
  confirm_duplicate: Duplicate this story?
826
846
  confirm_restore: Restore story to the selected version? A snapshot will be created, so that you can roll back later.
@@ -1172,6 +1192,11 @@ en:
1172
1192
  entries:
1173
1193
  unsupported_browser_hint:
1174
1194
  message: The Pageflow editor does not support the browser version you are using. We recommend upgrading your browser to the most recent version.
1195
+ entry_structured_data_types:
1196
+ article:
1197
+ label: Article
1198
+ faq_page:
1199
+ label: FAQ Page
1175
1200
  errors:
1176
1201
  UnmatchedUploadError: This filetype is not supported.
1177
1202
  invalid_nested_type_error: 'Error: Upload file ''%{name}'' is a %{type}. Only the following types of files are allowed: %{validList}'
@@ -1185,6 +1210,21 @@ en:
1185
1210
  video_settings_tab: Video Details
1186
1211
  files:
1187
1212
  common_attributes:
1213
+ ai_indicator:
1214
+ blank: "(Not specified)"
1215
+ inline_help: |-
1216
+ Indicate that the file has been generated or modified
1217
+ using artificial intelligence. Displayed as EU AI label
1218
+ at the element where the file is used.
1219
+ label: AI label
1220
+ values:
1221
+ ai_generated: Fully AI generated
1222
+ ai_modified: Partially AI modified
1223
+ ai_indicator_text:
1224
+ inline_help: |-
1225
+ Explains which parts of the file have been generated or
1226
+ modified using artificial intelligence.
1227
+ label: AI label text
1188
1228
  alt:
1189
1229
  inline_help: A hint describing the contents of the displayed element. Not displayed in the story, but can be used by screen reader software. Improves accessibility of the content.
1190
1230
  label: Alt-Text
@@ -1255,6 +1295,11 @@ en:
1255
1295
  failed: Transfer to S3 failed.
1256
1296
  finished: Successfully transferred to S3.
1257
1297
  pending: Transfer to S3 pending.
1298
+ singular:
1299
+ audio_files: an audio file
1300
+ image_files: an image
1301
+ other_files: a file
1302
+ video_files: a video
1258
1303
  tabs:
1259
1304
  audio_files: Audios
1260
1305
  image_files: Images
@@ -1372,13 +1417,18 @@ en:
1372
1417
  entry_preview:
1373
1418
  navigation_disabled_hint: Page changes not possible in phone preview.
1374
1419
  file_item:
1375
- cancel: Cancel
1420
+ actions: Actions
1421
+ cancel_upload: Cancel upload
1376
1422
  confirm: Confirm
1377
1423
  credits: Credits
1378
1424
  destroy: Delete
1379
1425
  download: Download
1380
1426
  expand_details: Show details
1381
1427
  collapse_details: Hide details
1428
+ move: Move...
1429
+ reference_count:
1430
+ one: 1 usage
1431
+ other: "%{count} usages"
1382
1432
  retry: Retry
1383
1433
  select: Select
1384
1434
  settings: Settings
@@ -1389,8 +1439,9 @@ en:
1389
1439
  close: Close
1390
1440
  files:
1391
1441
  back: Back
1442
+ in_folder: 'In folder:'
1392
1443
  files_blank_slate:
1393
- no_files: There are no files of this type, yet. You can upload one to get started.
1444
+ no_files: There are no files yet. You can upload one to get started.
1394
1445
  files_explorer:
1395
1446
  cancel: Cancel
1396
1447
  ok: Ok
@@ -1412,6 +1463,8 @@ en:
1412
1463
  list_search_field:
1413
1464
  placeholder: 'Filter files'
1414
1465
  hint: 'Type %{hotkey} to search'
1466
+ hint_in_all_folders: 'Type %{hotkey} to search all folders'
1467
+ hint_in_folder: 'Type %{hotkey} to search this folder'
1415
1468
  reset: 'Clear filter'
1416
1469
  loading:
1417
1470
  loading: Loading...
@@ -1468,8 +1521,6 @@ en:
1468
1521
  until_including: Until including
1469
1522
  user_name: User name
1470
1523
  view_revisions: View versions
1471
- select_button:
1472
- select: Select
1473
1524
  storyline_outline:
1474
1525
  header: Outline
1475
1526
  new_chapter: New chapter
@@ -1491,15 +1542,24 @@ en:
1491
1542
  title_loading_spinner:
1492
1543
  widget_type_info_box_text: This is a preview of the 'Title and Image' loading view. The animation runs while the page is loading.
1493
1544
  views:
1545
+ audio_file_preview_view:
1546
+ pause: Pause
1547
+ play: Play
1494
1548
  chapter_item_view:
1495
1549
  chapter: Chapter
1496
1550
  unnamed: "(New chapter)"
1551
+ confirmable_file_item_view:
1552
+ confirm_destroy: Really delete this file?
1497
1553
  edit_chapter_view:
1498
1554
  confirm_destroy: |-
1499
1555
  Really delete this chapter including ALL its pages?
1500
1556
 
1501
1557
  This operation cannot be undone.
1558
+ destroy_menu_item:
1559
+ confirm_destroy: Really delete this record? This action cannot be undone.
1560
+ destroy: Delete
1502
1561
  edit_configuration:
1562
+ actions: Actions
1503
1563
  back: "Back"
1504
1564
  confirm_destroy: Really delete this record? This action cannot be undone.
1505
1565
  destroy: Delete
@@ -1520,22 +1580,67 @@ en:
1520
1580
  show_editor: Show editor panel
1521
1581
  entry_preview_view:
1522
1582
  scroll_hint: Scroll down to continue
1583
+ file_item_view:
1584
+ confirm_destroy: Really delete this file?
1523
1585
  file_meta_data_item_value_view:
1524
1586
  blank: "-"
1587
+ file_references:
1588
+ header: Referenced by
1589
+ file_preview_progress_bar_view:
1590
+ position: Playback position
1591
+ files_blank_slate_view:
1592
+ empty_folder: 'This folder does not contain any files, yet.'
1593
+ no_matches: 'No file matches the current filter.'
1525
1594
  files_view:
1526
1595
  add: Add
1527
1596
  authenticating: Authenticating
1528
- import: Import
1597
+ folder: New folder
1598
+ import: Import file...
1529
1599
  importer:
1530
1600
  heading: Import files from
1531
- reuse: Reuse
1532
- upload: Upload
1601
+ reuse: Reuse file...
1602
+ tabs:
1603
+ files: Files
1604
+ upload: Upload file...
1605
+ file_type_pills_view:
1606
+ group_label: 'Filter by file type'
1607
+ hint: 'Click a file type to show only its files. Hold Ctrl/Cmd to combine file types.'
1533
1608
  filtered_files_view:
1534
- banner_prefix: 'Active filter:'
1609
+ actions: 'File list actions'
1610
+ any_file_type: 'a file'
1611
+ cancel_selection: 'Cancel selection'
1612
+ confirm_destroy_selection:
1613
+ one: 'Really delete 1 item?'
1614
+ other: 'Really delete %{count} items?'
1615
+ destroy_selection: 'Delete selection'
1616
+ end_selection: 'End selection'
1617
+ move_selection: 'Move...'
1618
+ reset_filter: 'Reset filter'
1619
+ search: 'Filter files and folders'
1620
+ search_in_folder: 'Filter files in %{folder}'
1621
+ select: 'Select %{name}'
1622
+ select_items: 'Select files and folders'
1623
+ selected_items:
1624
+ zero: 'No items selected'
1625
+ one: '1 item selected'
1626
+ other: '%{count} items selected'
1535
1627
  sort_button_label: 'Sort'
1536
1628
  sort:
1537
1629
  alphabetical: 'Alphabetical'
1538
1630
  most_recent: 'Most recent'
1631
+ folder_breadcrumb_view:
1632
+ label: 'Folder path'
1633
+ reset: 'Leave folder'
1634
+ folder_item_view:
1635
+ actions: 'Folder actions'
1636
+ destroy: 'Delete'
1637
+ file_count:
1638
+ one: '1 file'
1639
+ other: '%{count} files'
1640
+ move: 'Move...'
1641
+ name: 'Name of new folder'
1642
+ new_name: 'New name of folder'
1643
+ rename: 'Rename'
1539
1644
  inputs:
1540
1645
  file_input:
1541
1646
  auto_default_text_track: "(Auto)"
@@ -1549,6 +1654,35 @@ en:
1549
1654
  unset: Reset
1550
1655
  theme_input_view:
1551
1656
  choose: Change theme
1657
+ edit_defaults_input_view:
1658
+ label: Defaults for new elements
1659
+ oembed_url_input_view:
1660
+ status:
1661
+ resolving: "Resolving..."
1662
+ resolved: "Resolved"
1663
+ invalid_provider: "Invalid provider"
1664
+ not_found: "URL not found"
1665
+ error: "Error resolving URL"
1666
+ move_to_folder_dialog_view:
1667
+ cancel: 'Cancel'
1668
+ current: 'Current folder'
1669
+ header:
1670
+ files:
1671
+ one: 'Move file'
1672
+ other: 'Move files'
1673
+ folders:
1674
+ one: 'Move folder'
1675
+ other: 'Move folders'
1676
+ items: 'Move items'
1677
+ hint:
1678
+ files:
1679
+ one: 'Select the folder to move %{name} to.'
1680
+ other: 'Select the folder to move %{count} files to.'
1681
+ folders:
1682
+ one: 'Select the folder to move %{name} to.'
1683
+ other: 'Select the folder to move %{count} folders to.'
1684
+ items: 'Select the folder to move %{count} items to.'
1685
+ root: 'No folder'
1552
1686
  page_item_view:
1553
1687
  unnamed: "(New page)"
1554
1688
  page_link_item_view:
@@ -1557,6 +1691,9 @@ en:
1557
1691
  storylines_picker_view:
1558
1692
  label: Storyline
1559
1693
  without_parent_page: Without parent page
1694
+ video_file_preview_view:
1695
+ mute: Mute
1696
+ unmute: Unmute
1560
1697
  widgets:
1561
1698
  attributes:
1562
1699
  media_loading_spinner:
@@ -1921,10 +2058,15 @@ en:
1921
2058
  untitled: Unnamed storyline
1922
2059
  structured_data:
1923
2060
  feature_name: Embedded structured data
2061
+ faq_page_structured_data:
2062
+ feature_name: FAQ Page structured data
1924
2063
  title_loading_spinner:
1925
2064
  feature_name: "'Title and image' loading view"
1926
2065
  widget_type_name: Title and Image
1927
2066
  ui:
2067
+ color_picker:
2068
+ hue: "Hue"
2069
+ opacity: "Opacity"
1928
2070
  configuration_editor:
1929
2071
  tabs:
1930
2072
  consent_bar: Consent bar
@@ -2089,12 +2231,6 @@ en:
2089
2231
  next: ">>"
2090
2232
  previous: !!str '<<'
2091
2233
  truncate: "..."
2092
- pageflow_scrolled:
2093
- editor:
2094
- section_item:
2095
- set_cutoff: "Set paywall cutoff above"
2096
- reset_cutoff: "Remove paywall cutoff"
2097
- cutoff: "Paywall cutoff"
2098
2234
  activemodel:
2099
2235
  attributes:
2100
2236
  pageflow/site_root_entry_form:
data/config/routes.rb CHANGED
@@ -63,6 +63,8 @@ Pageflow::Engine.routes.draw do
63
63
  put :publish, on: :member
64
64
  end
65
65
 
66
+ resources :file_folders, only: [:index, :create, :update, :destroy]
67
+
66
68
  get '/file_import/:file_import_name/search' => 'file_import#search'
67
69
  post '/file_import/:file_import_name/files_meta_data' => 'file_import#files_meta_data'
68
70
  post '/file_import/:file_import_name/start_import_job' => 'file_import#start_import_job'
@@ -73,6 +75,18 @@ Pageflow::Engine.routes.draw do
73
75
  patch :batch, on: :collection
74
76
  end
75
77
  end
78
+
79
+ resource :oembed, only: [:show]
80
+ end
81
+
82
+ namespace :review do
83
+ resources :entries, only: [] do
84
+ resources :comment_threads, only: [:index, :create, :update] do
85
+ resources :comments, only: [:create, :update]
86
+ end
87
+
88
+ resources :comment_thread_reads, only: [:create]
89
+ end
76
90
  end
77
91
 
78
92
  root to: redirect('/admin')
@@ -1,4 +1,4 @@
1
- # rubocop:disable Layout/LineLength, Metrics/ClassLength, Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
1
+ # rubocop:disable Layout/LineLength, Metrics/ClassLength, Metrics/BlockLength
2
2
 
3
3
  class SetupSchema < ActiveRecord::Migration[5.2]
4
4
  def change
@@ -296,4 +296,4 @@ class SetupSchema < ActiveRecord::Migration[5.2]
296
296
  end
297
297
  end
298
298
 
299
- # rubocop:enable Layout/LineLength, Metrics/ClassLength, Metrics/MethodLength, Metrics/AbcSize, Metrics/BlockLength
299
+ # rubocop:enable Layout/LineLength, Metrics/ClassLength, Metrics/BlockLength
@@ -0,0 +1,5 @@
1
+ class AddStructuredDataTypeNameToRevisions < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :pageflow_revisions, :structured_data_type_name, :string
4
+ end
5
+ end
@@ -0,0 +1,38 @@
1
+ # This migration should run in a separate deploy after the application code
2
+ # that supports the 'socialEmbed' content element type has been deployed.
3
+ # Running this migration before deploying the new code will cause errors
4
+ # when old versions of the app encounter 'socialEmbed' content elements
5
+ # they don't recognize. For zero-downtime deployments:
6
+ #
7
+ # 1. First deploy: Deploy application code with 'socialEmbed' support
8
+ # AND enable_by_default for 'legacy_social_embed_content_elements'
9
+ # feature flag (to keep tikTokEmbed and twitterEmbed working)
10
+ # 2. Run this migration to convert legacy elements to socialEmbed
11
+ # 3. Second deploy: Remove enable_by_default from legacy flag and
12
+ # enable_by_default for 'social_embed_content_element' feature flag
13
+ #
14
+ class ConvertLegacySocialEmbedsToUnifiedSocialEmbed < ActiveRecord::Migration[7.1]
15
+ class MigratedContentElement < ActiveRecord::Base
16
+ self.table_name = 'pageflow_scrolled_content_elements'
17
+
18
+ serialize :configuration, coder: JSON
19
+ end
20
+
21
+ def up
22
+ convert_type('tikTokEmbed', 'tiktok')
23
+ convert_type('twitterEmbed', 'x')
24
+ end
25
+
26
+ def down; end
27
+
28
+ private
29
+
30
+ def convert_type(old_type_name, provider)
31
+ MigratedContentElement.where(type_name: old_type_name).find_each(batch_size: 100) do |element|
32
+ element.configuration ||= {}
33
+ element.configuration['provider'] = provider
34
+ element.type_name = 'socialEmbed'
35
+ element.save!
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ # Fix bug in EnsureScrolledEntriesHaveMainStoryline migration which created
2
+ # main storylines at position 1 instead of 0. Main storylines should be at
3
+ # position 0, excursion storylines at position 1.
4
+ class FixMainStorylinePositions < ActiveRecord::Migration[7.1]
5
+ def up
6
+ execute(<<-SQL)
7
+ UPDATE pageflow_scrolled_storylines
8
+ SET position = 0
9
+ WHERE configuration IS NOT NULL
10
+ AND configuration LIKE '%"main"%true%'
11
+ AND position != 0;
12
+ SQL
13
+ end
14
+
15
+ def down; end
16
+ end
@@ -0,0 +1,15 @@
1
+ class EnsureScrolledEntriesHaveExcursionStoryline < ActiveRecord::Migration[7.1]
2
+ def up
3
+ execute(<<-SQL)
4
+ INSERT INTO pageflow_scrolled_storylines (revision_id, perma_id, position, created_at, updated_at)
5
+ SELECT r.id, main_storyline.perma_id + 1, 1, NOW(), NOW()
6
+ FROM pageflow_revisions r
7
+ INNER JOIN pageflow_entries e ON r.entry_id = e.id
8
+ INNER JOIN pageflow_scrolled_storylines main_storyline ON main_storyline.revision_id = r.id AND main_storyline.position = 0
9
+ LEFT JOIN pageflow_scrolled_storylines excursion_storyline ON excursion_storyline.revision_id = r.id AND excursion_storyline.position = 1
10
+ WHERE e.type_name = 'scrolled' AND excursion_storyline.id IS NULL;
11
+ SQL
12
+ end
13
+
14
+ def down; end
15
+ end
@@ -0,0 +1,6 @@
1
+ class AddLayoutVersionToRevisions < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :pageflow_revisions, :layout_version, :integer
4
+ change_column_default :pageflow_revisions, :layout_version, from: nil, to: 1
5
+ end
6
+ end
@@ -0,0 +1,30 @@
1
+ class CreateCommentThreadsAndComments < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :pageflow_comment_threads do |t|
4
+ t.integer :revision_id, null: false
5
+ t.integer :perma_id
6
+ t.string :subject_type, null: false
7
+ t.integer :subject_id, null: false
8
+ t.integer :creator_id, null: false
9
+ t.datetime :resolved_at
10
+ t.integer :resolved_by_id
11
+ t.timestamps
12
+ end
13
+
14
+ add_index :pageflow_comment_threads, :revision_id
15
+ add_index :pageflow_comment_threads, :creator_id
16
+ add_index :pageflow_comment_threads, [:revision_id, :subject_type, :subject_id],
17
+ name: 'index_comment_threads_on_revision_and_subject'
18
+
19
+ create_table :pageflow_comments do |t|
20
+ t.integer :comment_thread_id, null: false
21
+ t.integer :perma_id
22
+ t.integer :creator_id, null: false
23
+ t.text :body, null: false
24
+ t.timestamps
25
+ end
26
+
27
+ add_index :pageflow_comments, :comment_thread_id
28
+ add_index :pageflow_comments, :creator_id
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ class AddSubjectRangeToCommentThreads < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :pageflow_comment_threads, :subject_range, :text
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddSectionPermaIdToCommentThreads < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :pageflow_comment_threads, :section_perma_id, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddQuoteToComments < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :pageflow_comments, :quote, :text
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ class CreateFileFolders < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :pageflow_file_folders do |t|
4
+ t.integer :revision_id, null: false
5
+ t.integer :perma_id
6
+ t.integer :parent_folder_perma_id
7
+ t.string :name, null: false
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :pageflow_file_folders, [:revision_id, :perma_id]
12
+ add_index :pageflow_file_folders, [:revision_id, :parent_folder_perma_id],
13
+ name: 'index_file_folders_on_revision_and_parent_folder'
14
+
15
+ add_column :pageflow_file_usages, :folder_perma_id, :integer
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ class AddAttributeTranslationsToSites < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :pageflow_sites, :attribute_translations, :text
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddEditedAtToComments < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :pageflow_comments, :edited_at, :datetime
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ class CreatePageflowScrolledLottieFiles < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :pageflow_scrolled_lottie_files do |t|
4
+ t.belongs_to :entry, index: true
5
+ t.belongs_to :uploader, index: true
6
+
7
+ t.bigint 'parent_file_id'
8
+ t.string 'parent_file_model_type'
9
+
10
+ t.string 'state'
11
+ t.string 'rights'
12
+
13
+ t.string 'attachment_on_s3_file_name'
14
+ t.string 'attachment_on_s3_content_type'
15
+ t.bigint 'attachment_on_s3_file_size'
16
+ t.datetime 'attachment_on_s3_updated_at'
17
+
18
+ t.timestamps
19
+
20
+ t.index ['parent_file_id', 'parent_file_model_type'],
21
+ name: 'index_lottie_files_on_parent_id_and_parent_model_type'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ class CreateCommentThreadReads < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :pageflow_comment_thread_reads do |t|
4
+ t.integer :entry_id, null: false
5
+ t.integer :user_id, null: false
6
+ t.integer :comment_thread_perma_id, null: false
7
+ t.datetime :read_at, null: false
8
+ end
9
+
10
+ add_index :pageflow_comment_thread_reads,
11
+ [:user_id, :entry_id, :comment_thread_perma_id],
12
+ unique: true,
13
+ name: 'index_comment_thread_reads_on_user_and_entry_and_thread'
14
+ add_index :pageflow_comment_thread_reads, :entry_id
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ class AddUnreadCommentsSinceAtToUsers < ActiveRecord::Migration[7.1]
2
+ class MigratedUser < ActiveRecord::Base
3
+ self.table_name = 'users'
4
+ end
5
+
6
+ def up
7
+ add_column :users, :unread_comments_since_at, :datetime
8
+
9
+ # Comments written before the feature existed have not gone unread:
10
+ # without a baseline, every one of them would turn up as unread for
11
+ # every user at once.
12
+ MigratedUser.update_all(unread_comments_since_at: Time.current)
13
+ end
14
+
15
+ def down
16
+ remove_column :users, :unread_comments_since_at
17
+ end
18
+ end