apostrophe 4.28.0 → 4.29.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 (88) hide show
  1. package/CHANGELOG.md +33 -3
  2. package/README.md +142 -0
  3. package/defaults.js +1 -0
  4. package/lib/safe-json-script.js +27 -0
  5. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +1 -1
  6. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +1 -0
  7. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +3 -5
  8. package/modules/@apostrophecms/area/ui/apos/components/AposBreadcrumbOperations.vue +13 -1
  9. package/modules/@apostrophecms/asset/lib/globalIcons.js +3 -0
  10. package/modules/@apostrophecms/attachment/index.js +43 -1
  11. package/modules/@apostrophecms/color-field/index.js +7 -1
  12. package/modules/@apostrophecms/doc/index.js +11 -1
  13. package/modules/@apostrophecms/doc-type/index.js +165 -32
  14. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +1 -1
  15. package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +104 -59
  16. package/modules/@apostrophecms/file/index.js +109 -9
  17. package/modules/@apostrophecms/i18n/i18n/de.json +0 -2
  18. package/modules/@apostrophecms/i18n/i18n/en.json +40 -1
  19. package/modules/@apostrophecms/i18n/i18n/es.json +0 -1
  20. package/modules/@apostrophecms/i18n/i18n/fr.json +0 -1
  21. package/modules/@apostrophecms/i18n/i18n/it.json +0 -1
  22. package/modules/@apostrophecms/i18n/i18n/pt-BR.json +0 -1
  23. package/modules/@apostrophecms/i18n/i18n/sk.json +0 -1
  24. package/modules/@apostrophecms/i18n/ui/apos/apps/AposI18nBatchReporting.js +18 -1
  25. package/modules/@apostrophecms/i18n/ui/apos/apps/AposI18nLocalizeActions.js +50 -0
  26. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +56 -13
  27. package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +8 -2
  28. package/modules/@apostrophecms/layout-column-widget/index.js +156 -163
  29. package/modules/@apostrophecms/layout-widget/index.js +7 -2
  30. package/modules/@apostrophecms/layout-widget/ui/apos/components/AposAreaLayoutEditor.vue +6 -11
  31. package/modules/@apostrophecms/layout-widget/ui/apos/components/AposGridColumn.vue +3 -5
  32. package/modules/@apostrophecms/layout-widget/ui/apos/components/AposGridLayout.vue +4 -4
  33. package/modules/@apostrophecms/layout-widget/ui/apos/components/AposGridManager.vue +0 -16
  34. package/modules/@apostrophecms/layout-widget/ui/apos/lib/grid-state.mjs +7 -27
  35. package/modules/@apostrophecms/layout-widget/views/column.html +7 -9
  36. package/modules/@apostrophecms/login/index.js +39 -40
  37. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +17 -2
  38. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +3 -2
  39. package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +1 -0
  40. package/modules/@apostrophecms/page/index.js +2 -0
  41. package/modules/@apostrophecms/piece-type/index.js +3 -1
  42. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +1 -0
  43. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +5 -0
  44. package/modules/@apostrophecms/recently-edited/index.js +831 -0
  45. package/modules/@apostrophecms/recently-edited/ui/apos/components/AposCellTitle.vue +54 -0
  46. package/modules/@apostrophecms/recently-edited/ui/apos/components/AposRecentlyEditedCombo.vue +454 -0
  47. package/modules/@apostrophecms/recently-edited/ui/apos/components/AposRecentlyEditedFilterTag.vue +75 -0
  48. package/modules/@apostrophecms/recently-edited/ui/apos/components/AposRecentlyEditedFilters.vue +287 -0
  49. package/modules/@apostrophecms/recently-edited/ui/apos/components/AposRecentlyEditedIcon.vue +16 -0
  50. package/modules/@apostrophecms/recently-edited/ui/apos/components/AposRecentlyEditedManager.vue +346 -0
  51. package/modules/@apostrophecms/recently-edited/ui/apos/composables/useRecentlyEditedBatch.js +193 -0
  52. package/modules/@apostrophecms/recently-edited/ui/apos/composables/useRecentlyEditedData.js +276 -0
  53. package/modules/@apostrophecms/recently-edited/ui/apos/composables/useRecentlyEditedFetch.js +199 -0
  54. package/modules/@apostrophecms/recently-edited/ui/apos/composables/useRecentlyEditedFilters.js +100 -0
  55. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRelationship.js +8 -4
  56. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputWrapper.js +1 -1
  57. package/modules/@apostrophecms/styles/index.js +10 -0
  58. package/modules/@apostrophecms/styles/lib/apiRoutes.js +6 -0
  59. package/modules/@apostrophecms/styles/lib/handlers.js +5 -0
  60. package/modules/@apostrophecms/styles/lib/methods.js +9 -3
  61. package/modules/@apostrophecms/styles/lib/presets.js +119 -0
  62. package/modules/@apostrophecms/styles/ui/apos/components/TheAposStyles.vue +3 -8
  63. package/modules/@apostrophecms/styles/ui/apos/composables/AposStyles.js +1 -3
  64. package/modules/@apostrophecms/styles/ui/apos/render-factory.js +29 -0
  65. package/modules/@apostrophecms/styles/ui/apos/universal/backgroundHelpers.mjs +140 -0
  66. package/modules/@apostrophecms/styles/ui/apos/universal/customRules.mjs +105 -0
  67. package/modules/@apostrophecms/styles/ui/apos/universal/render.mjs +195 -15
  68. package/modules/@apostrophecms/template/index.js +22 -6
  69. package/modules/@apostrophecms/ui/ui/apos/components/AposCellContextMenu.vue +2 -0
  70. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +18 -4
  71. package/modules/@apostrophecms/ui/ui/apos/composables/useInfiniteScroll.js +91 -0
  72. package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +1 -0
  73. package/modules/@apostrophecms/ui/ui/apos/stores/modal.js +5 -2
  74. package/modules/@apostrophecms/ui/ui/apos/utils/index.js +9 -0
  75. package/modules/@apostrophecms/url/index.js +38 -4
  76. package/modules/@apostrophecms/widget-type/index.js +22 -6
  77. package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +8 -4
  78. package/package.json +19 -19
  79. package/test/files.js +129 -0
  80. package/test/layout-widget-migration.js +719 -0
  81. package/test/login-requirements.js +1 -1
  82. package/test/pieces-public-api.js +80 -0
  83. package/test/pieces.js +25 -0
  84. package/test/recently-edited.js +2311 -0
  85. package/test/schemas.js +39 -3
  86. package/test/static-build.js +642 -0
  87. package/test/styles.js +2569 -0
  88. package/modules/@apostrophecms/layout-widget/ui/apos/components/AposLayoutColControlDialog.vue +0 -171
@@ -287,6 +287,7 @@
287
287
  "insertTable": "Insert Table",
288
288
  "invalid": "invalid",
289
289
  "lastEdited": "Last Edited",
290
+ "lastEditor": "Last Editor",
290
291
  "lastUpdatedBy": "Last saved on {{ updatedAt }} <br /> by {{ updatedBy }}",
291
292
  "layout": "Layout",
292
293
  "layoutAlign": "Vertical alignment",
@@ -318,6 +319,7 @@
318
319
  "listJoiner": ", ",
319
320
  "live": "Live",
320
321
  "loadDocFailed": "The requested document was not found.",
322
+ "loadingMore": "Loading more...",
321
323
  "locale": "Locale",
322
324
  "localeSwitcherDiscardChangesAffirmative": "Save as draft and switch",
323
325
  "localeSwitcherDiscardChangesNegative": "Discard changes and switch",
@@ -326,10 +328,12 @@
326
328
  "localize": "Localize...",
327
329
  "localizeAllRelated": "Localize all related documents and overwrite existing documents",
328
330
  "localizeContent": "Localize Content",
331
+ "localizeEditDocument": "Edit document",
329
332
  "localizeLocalized": "Localized",
333
+ "localizeManageDocuments": "Manage documents",
330
334
  "localizeNewRelated": "Localize new related documents",
331
335
  "localizeNotYetLocalized": "Not Yet Localized",
332
- "localized": "Localized the {{ type }} {{ title }} to {{ locale }}",
336
+ "localizeOpenDocument": "View document",
333
337
  "localizedBatch": "Processed {{ count }} {{ type }}",
334
338
  "localizedBatchFailed": "Localizing {{ type }} failed",
335
339
  "localizedBatchWithFailures": "Processed {{ count }} {{ type }} ({{ bad }} of {{ total }} failed)",
@@ -444,6 +448,7 @@
444
448
  "pageNumber": "Page {{ number }}",
445
449
  "pageTitle": "Page Title",
446
450
  "pages": "Pages",
451
+ "pieces": "Pieces",
447
452
  "parentNotLocalized": "Localize the parent page first",
448
453
  "password": "Password",
449
454
  "passwordChangeHelp": "Modify your existing password",
@@ -476,6 +481,29 @@
476
481
  "rawHtml": "Raw HTML",
477
482
  "rawHtmlCode": "Raw HTML (Code)",
478
483
  "rawHtmlCodeHelp": "Be careful when embedding third-party code, as it can break the website editing functionality. If a page becomes unusable, add \"?safe_mode=1\" to the URL to make it work temporarily without the problem code being rendered.",
484
+ "recentlyEdited": "Recently edited",
485
+ "recentlyEditedAction": "Action",
486
+ "recentlyEditedResetFilters": "Reset filters",
487
+ "recentlyEditedActionCreated": "Created",
488
+ "recentlyEditedActionLocalized": "Localized",
489
+ "recentlyEditedActionPublished": "Published",
490
+ "recentlyEditedActionSubmitted": "Submitted",
491
+ "recentlyEditedCurrentUser": "Me ({{ user }})",
492
+ "recentlyEditedDocuments": "Recently edited documents",
493
+ "recentlyEditedEditedBy": "Edited by",
494
+ "recentlyEditedClearAllFilters": "Clear all filters",
495
+ "recentlyEditedClearSearch": "Clear search",
496
+ "recentlyEditedEmpty": "No recently edited documents found in the past {{ count }} day",
497
+ "recentlyEditedEmpty_plural": "No recently edited documents found in the past {{ count }} days",
498
+ "recentlyEditedEmptyFiltered": "No documents match your current filters",
499
+ "recentlyEditedEmptyFilteredHint": "Try adjusting or clearing your filters to see more results",
500
+ "recentlyEditedEmptySearched": "No documents match your search",
501
+ "recentlyEditedEmptySearchedHint": "Try different search terms or adjust your filters",
502
+ "recentlyEditedFilters": "Filters",
503
+ "recentlyEditedSearchDocuments": "Search documents",
504
+ "recentlyEditedAddFilter": "Add filter value",
505
+ "recentlyEditedStatus": "Status",
506
+ "recentlyEditedStatusSubmitted": "Submitted",
479
507
  "redo": "Redo",
480
508
  "redoFailed": "The operation could not be redone.",
481
509
  "redoTooltip": "Redo Change",
@@ -600,14 +628,25 @@
600
628
  "splitCell": "Split Cell",
601
629
  "style": "Style",
602
630
  "styleAlignment": "Alignment",
631
+ "styleBackground": "Background",
632
+ "styleBackgroundColor": "Color",
633
+ "styleBackgroundGradient": "Gradient",
634
+ "styleBackgroundImage": "Image",
635
+ "styleBackgroundOverlay": "Overlay",
636
+ "styleBackgroundType": "Background Type",
603
637
  "styleBorder": "Border",
604
638
  "styleBorderWidth": "Border Width",
605
639
  "styleCenter": "Center",
606
640
  "styleColor": "Border Color",
607
641
  "styleDashed": "Dashed",
608
642
  "styleDotted": "Dotted",
643
+ "styleGradientAngle": "Angle",
644
+ "styleGradientEnd": "End Color",
645
+ "styleGradientStart": "Start Color",
609
646
  "styleLeft": "Left",
610
647
  "styleMargin": "Margin",
648
+ "styleOverlayColor": "Overlay Color",
649
+ "styleOverlayOpacity": "Overlay Opacity",
611
650
  "stylePadding": "Padding",
612
651
  "styleRadius": "Radius",
613
652
  "styleRight": "Right",
@@ -324,7 +324,6 @@
324
324
  "localizeLocalized": "Localizado",
325
325
  "localizeNewRelated": "Traducir nuevos documentos relacionados",
326
326
  "localizeNotYetLocalized": "No localizado aún",
327
- "localized": "El {{ type }} {{ title }} ha sido traducido a la configuración regional {{ locale }}",
328
327
  "localizedBatch": "Procesado {{ count }} {{ type }}",
329
328
  "localizedBatchFailed": "Error al localizar {{ type }}",
330
329
  "localizedBatchWithFailures": "Procesado {{ count }} {{ type }} ({{ bad }} de {{ total }} fallaron)",
@@ -324,7 +324,6 @@
324
324
  "localizeLocalized": "Localisé",
325
325
  "localizeNewRelated": "Changer la langue des nouveaux documents associés",
326
326
  "localizeNotYetLocalized": "Pas encore localisé",
327
- "localized": "{{ type }} {{ title }} changé en {{ locale }}",
328
327
  "localizedBatch": "Traité {{ count }} {{ type }}",
329
328
  "localizedBatchFailed": "La localisation de {{ type }} a échoué.",
330
329
  "localizedBatchWithFailures": "Traité {{ count }} {{ type }} ({{ bad }} sur {{ total }} ont échoué).",
@@ -324,7 +324,6 @@
324
324
  "localizeLocalized": "Localizzato",
325
325
  "localizeNewRelated": "Localizza nuovi documenti correlati",
326
326
  "localizeNotYetLocalized": "Non ancora localizzato",
327
- "localized": "Localizzato il {{ type }} {{ title }} in {{ locale }}",
328
327
  "localizedBatch": "Elaborato {{ count }} {{ type }}",
329
328
  "localizedBatchFailed": "Localizzazione di {{ type }} fallita",
330
329
  "localizedBatchWithFailures": "Elaborato {{ count }} {{ type }} ({{ bad }} di {{ total }} fallito)",
@@ -324,7 +324,6 @@
324
324
  "localizeLocalized": "Localizado",
325
325
  "localizeNewRelated": "Localizar novos documentos relacionados",
326
326
  "localizeNotYetLocalized": "Ainda Não Localizado",
327
- "localized": "Localizar o(a) {{ type }} {{ title }} para {{ locale }}",
328
327
  "localizedBatch": "Processado {{ count }} {{ type }}",
329
328
  "localizedBatchFailed": "Falha ao localizar {{ type }}",
330
329
  "localizedBatchWithFailures": "Processado {{ count }} {{ type }} ({{ bad }} de {{ total }} falharam)",
@@ -324,7 +324,6 @@
324
324
  "localizeLocalized": "Lokalizované",
325
325
  "localizeNewRelated": "Preložte nové súvisiace dokumenty",
326
326
  "localizeNotYetLocalized": "Ešte nie je lokalizované",
327
- "localized": "Preložené {{ type }} {{ title }} do {{ locale }}",
328
327
  "localizedBatch": "Spracované {{ count }} {{ type }}",
329
328
  "localizedBatchFailed": "Lokalizácia {{ type }} zlyhala",
330
329
  "localizedBatchWithFailures": "Spracované {{ count }} {{ type }} ({{ bad }} z {{ total }} zlyhalo)",
@@ -16,11 +16,28 @@ export default () => {
16
16
 
17
17
  if (!skipCount) {
18
18
  if (count) {
19
+ const targetLocales = [ ...new Set(
20
+ log.filter(isSuccess).map(entry => entry.locale)
21
+ ) ];
22
+ const managerOpen = apos.modal.get()
23
+ .some(modal => modal.componentName === 'AposRecentlyEditedManager');
19
24
  await apos.notify('apostrophe:localizingNotificationSuccess', {
20
25
  type: 'success',
21
26
  icon: 'translate-icon',
22
27
  interpolate: { count },
23
- dismiss: true
28
+ dismiss: managerOpen,
29
+ ...!managerOpen && {
30
+ buttons: [
31
+ {
32
+ type: 'event',
33
+ label: 'apostrophe:localizeManageDocuments',
34
+ name: 'localize-manage-documents',
35
+ data: {
36
+ locales: targetLocales
37
+ }
38
+ }
39
+ ]
40
+ }
24
41
  });
25
42
  }
26
43
  return;
@@ -0,0 +1,50 @@
1
+ export default () => {
2
+ let once = false;
3
+
4
+ apos.util.onReady(() => {
5
+ if (once) {
6
+ return;
7
+ }
8
+ once = true;
9
+
10
+ apos.bus.$on('localize-open-document', openDocument);
11
+ apos.bus.$on('localize-manage-documents', manageDocuments);
12
+ });
13
+
14
+ function openDocument(data) {
15
+ if (!data) {
16
+ return;
17
+ }
18
+ if (data._url) {
19
+ window.open(data._url, '_blank');
20
+ return;
21
+ }
22
+ const docModuleName = data.slug?.startsWith('/')
23
+ ? '@apostrophecms/page'
24
+ : data.type;
25
+ if (!apos.modules[docModuleName]) {
26
+ return;
27
+ }
28
+ const editorComponent = apos.modules[docModuleName]?.components?.editorModal || 'AposDocEditor';
29
+ apos.modal.execute(editorComponent, {
30
+ moduleName: docModuleName,
31
+ docId: data._id,
32
+ locale: data.locale
33
+ });
34
+ }
35
+
36
+ function manageDocuments(data) {
37
+ if (!data) {
38
+ return;
39
+ }
40
+ apos.bus.$emit('admin-menu-click', {
41
+ itemName: '@apostrophecms/recently-edited:manager',
42
+ props: {
43
+ initialFilters: {
44
+ _action: [ 'localized' ],
45
+ _locale: data.locales || []
46
+ }
47
+ }
48
+ });
49
+ }
50
+ };
@@ -317,7 +317,7 @@ export default {
317
317
  type: Object,
318
318
  default: null
319
319
  },
320
- locale: {
320
+ targetLocale: {
321
321
  required: false,
322
322
  type: Object,
323
323
  default: null
@@ -385,7 +385,7 @@ export default {
385
385
  title: this.$t('apostrophe:selectLocales'),
386
386
  filter: '',
387
387
  if() {
388
- return !this.locale;
388
+ return !this.targetLocale;
389
389
  },
390
390
  complete() {
391
391
  return this.selectedLocales.length > 0;
@@ -409,7 +409,7 @@ export default {
409
409
  },
410
410
  values: {
411
411
  toLocalize: { data: 'thisDocAndRelated' },
412
- toLocales: { data: this.locale ? [ this.locale ] : [] },
412
+ toLocales: { data: this.targetLocale ? [ this.targetLocale ] : [] },
413
413
  relatedDocSettings: { data: 'localizeNewRelated' },
414
414
  relatedDocTypesToLocalize: { data: [] },
415
415
  translateContent: { data: false },
@@ -836,7 +836,7 @@ export default {
836
836
  this.modal.busy = true;
837
837
  for (const locale of this.selectedLocales) {
838
838
  try {
839
- await apos.http.post(`${apos.modules[doc.type].action}/${doc._id}/localize`, {
839
+ const result = await apos.http.post(`${apos.modules[doc.type].action}/${doc._id}/localize`, {
840
840
  body: {
841
841
  toLocale: locale.name,
842
842
  update: (doc._id === this.fullDoc._id) || !(this.wizard.values.relatedDocSettings.data === 'localizeNewRelated')
@@ -853,10 +853,11 @@ export default {
853
853
  locale,
854
854
  docTypeLabel: this.singular(doc.type),
855
855
  doc,
856
+ result,
856
857
  relationship: doc._id === this.fullDoc._id
857
858
  });
858
859
 
859
- if (this.locale && this.shouldRedirect) {
860
+ if (this.targetLocale && this.shouldRedirect) {
860
861
  // Ask for the redirect URL, this way it still works if we
861
862
  // need to carry a session across hostnames
862
863
  const result = await apos.http.post(`${this.moduleOptions.action}/locale`, {
@@ -938,15 +939,57 @@ export default {
938
939
  }
939
940
  );
940
941
  } else {
941
- for (const item of notifications) {
942
- await apos.notify('apostrophe:localized', {
942
+ const successes = notifications.filter(({ type }) => type === 'success');
943
+ const count = successes.length;
944
+ const targetLocales = [ ...new Set(successes.map(item => item.locale.name)) ];
945
+ const managerOpen = apos.modal.get()
946
+ .some(modal => modal.componentName === 'AposRecentlyEditedManager');
947
+
948
+ if (count === 1) {
949
+ const item = successes[0];
950
+ const hasUrl = !!item.result?._url;
951
+ await apos.notify('apostrophe:localizingNotificationSuccess', {
943
952
  type: 'success',
944
- interpolate: {
945
- type: this.$t(this.singular(item.doc.type)),
946
- title: item.doc.title,
947
- locale: item.locale.name
948
- },
949
- dismiss: true
953
+ icon: 'translate-icon',
954
+ interpolate: { count },
955
+ dismiss: managerOpen,
956
+ ...!managerOpen && {
957
+ buttons: [
958
+ {
959
+ type: 'event',
960
+ label: hasUrl
961
+ ? 'apostrophe:localizeOpenDocument'
962
+ : 'apostrophe:localizeEditDocument',
963
+ name: 'localize-open-document',
964
+ data: {
965
+ _url: item.result?._url || null,
966
+ type: item.doc.type,
967
+ _id: item.result?._id || null,
968
+ locale: item.locale.name,
969
+ slug: item.result?.slug || item.doc.slug
970
+ }
971
+ }
972
+ ]
973
+ }
974
+ });
975
+ } else if (count > 1) {
976
+ await apos.notify('apostrophe:localizingNotificationSuccess', {
977
+ type: 'success',
978
+ icon: 'translate-icon',
979
+ interpolate: { count },
980
+ dismiss: managerOpen,
981
+ ...!managerOpen && {
982
+ buttons: [
983
+ {
984
+ type: 'event',
985
+ label: 'apostrophe:localizeManageDocuments',
986
+ name: 'localize-manage-documents',
987
+ data: {
988
+ locales: targetLocales
989
+ }
990
+ }
991
+ ]
992
+ }
950
993
  });
951
994
  }
952
995
  }
@@ -290,21 +290,27 @@ export default {
290
290
  };
291
291
  },
292
292
  async submit() {
293
+ let attachment;
293
294
  if (this.image.attachment) {
294
- await apos.http.post(`${apos.attachment.action}/crop`, {
295
+ attachment = await apos.http.post(`${apos.attachment.action}/crop`, {
295
296
  body: {
296
297
  _id: this.image.attachment._id,
297
- crop: this.docFields.data
298
+ crop: this.docFields.data,
299
+ annotate: true
298
300
  },
299
301
  busy: true
300
302
  });
301
303
  }
302
304
 
303
305
  if (!this.widget) {
306
+ if (attachment) {
307
+ this.image.attachment = attachment;
308
+ }
304
309
  this.$emit('modal-result', this.docFields.data);
305
310
  } else {
306
311
  const image = {
307
312
  ...this.image,
313
+ ...(attachment && { attachment }),
308
314
  _fields: this.docFields.data
309
315
  };
310
316
  const widget = {