apostrophe 3.53.0 → 3.55.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 (77) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/defaults.js +1 -0
  3. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextModeAndSettings.vue +5 -2
  4. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +28 -19
  5. package/modules/@apostrophecms/any-doc-type/index.js +2 -2
  6. package/modules/@apostrophecms/any-page-type/index.js +2 -2
  7. package/modules/@apostrophecms/doc/index.js +55 -29
  8. package/modules/@apostrophecms/doc-type/index.js +11 -6
  9. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +4 -440
  10. package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +445 -0
  11. package/modules/@apostrophecms/i18n/i18n/de.json +113 -105
  12. package/modules/@apostrophecms/i18n/i18n/es.json +10 -0
  13. package/modules/@apostrophecms/i18n/i18n/fr.json +8 -0
  14. package/modules/@apostrophecms/i18n/i18n/pt-BR.json +10 -0
  15. package/modules/@apostrophecms/i18n/i18n/sk.json +8 -0
  16. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +1 -0
  17. package/modules/@apostrophecms/log/index.js +429 -0
  18. package/modules/@apostrophecms/login/index.js +47 -4
  19. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +14 -1
  20. package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +1 -1
  21. package/modules/@apostrophecms/module/index.js +32 -6
  22. package/modules/@apostrophecms/module/lib/log.js +68 -0
  23. package/modules/@apostrophecms/page/index.js +71 -19
  24. package/modules/@apostrophecms/page/lib/legacy-migrations.js +0 -57
  25. package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +8 -285
  26. package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +291 -0
  27. package/modules/@apostrophecms/page-type/index.js +39 -26
  28. package/modules/@apostrophecms/piece-type/index.js +19 -11
  29. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +1 -0
  30. package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +2 -357
  31. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArea.vue +2 -86
  32. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +2 -254
  33. package/modules/@apostrophecms/schema/ui/apos/components/AposInputAttachment.vue +2 -77
  34. package/modules/@apostrophecms/schema/ui/apos/components/AposInputBoolean.vue +2 -44
  35. package/modules/@apostrophecms/schema/ui/apos/components/AposInputCheckboxes.vue +2 -64
  36. package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +2 -94
  37. package/modules/@apostrophecms/schema/ui/apos/components/AposInputDateAndTime.vue +3 -47
  38. package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +2 -82
  39. package/modules/@apostrophecms/schema/ui/apos/components/AposInputPassword.vue +2 -37
  40. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRadio.vue +2 -26
  41. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +2 -57
  42. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +2 -259
  43. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +2 -38
  44. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +2 -275
  45. package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +2 -167
  46. package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +2 -115
  47. package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +3 -279
  48. package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +2 -83
  49. package/modules/@apostrophecms/schema/ui/apos/lib/detectChange.js +10 -1
  50. package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +361 -0
  51. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArea.js +89 -0
  52. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArray.js +257 -0
  53. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputAttachment.js +81 -0
  54. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputBoolean.js +48 -0
  55. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputCheckboxes.js +68 -0
  56. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputColor.js +98 -0
  57. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputDateAndTime.js +49 -0
  58. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputObject.js +86 -0
  59. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputPassword.js +41 -0
  60. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRadio.js +29 -0
  61. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRange.js +60 -0
  62. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRelationship.js +262 -0
  63. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSelect.js +41 -0
  64. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +278 -0
  65. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputString.js +170 -0
  66. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputWrapper.js +118 -0
  67. package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +281 -0
  68. package/modules/@apostrophecms/schema/ui/apos/logic/AposSearchList.js +85 -0
  69. package/modules/@apostrophecms/template/index.js +1 -1
  70. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeHeader.vue +2 -2
  71. package/modules/@apostrophecms/util/index.js +83 -13
  72. package/modules/@apostrophecms/util/lib/logger.js +19 -17
  73. package/package.json +1 -1
  74. package/test/docs.js +35 -2
  75. package/test/log.js +1765 -0
  76. package/test/pages.js +57 -0
  77. package/test-lib/util.js +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.55.0
4
+
5
+ ### Adds
6
+
7
+ * Add `publicApiCheckAsync` wrapper method (and use it internally) to allow for overrides to do async permission checks of REST APIs. This feature doesn't introduce any breaking changes because the default implementation still invokes `publicApiCheck` in case developers have overridden it.
8
+
9
+ ### Fixes
10
+
11
+ * Refresh schema field with same name in `AposDocEditor` when the schema changes.
12
+ * Infer parent ID mode from the request when retrieving the parent (target) page to avoid `notfound`.
13
+ * Log the actual REST API error message and not the one meant for the user.
14
+ * Hide dash on autopublished pages title.
15
+
16
+ ## 3.54.0 (2023-08-16)
17
+
18
+ ### Adds
19
+
20
+ * Add `@apostrophecms/log` module to allow structured logging. All modules have `logDebug`, `logInfo`, `logWarn` and `logError` methods now. See the [documentation](https://v3.docs.apostrophecms.org/guide/logging.html) for more details.
21
+ * Add `@apostrophecms/settings` translations.
22
+ * Add the ability to have custom modals for batch operations.
23
+ * Add the possibility to display utility operations inside a 3-dots menu on the page manager, the same way it is done for the docs manager.
24
+ * Custom context operations now accept a `moduleIf` property, which tests options at the module level
25
+ the same way that `if` tests properties of the document to determine if the operation should be
26
+ offered for a particular document. Note that not all options are passed to the front end unless
27
+ `getBrowserData` is extended to suit the need.
28
+ * Move Pages Manager modal business logic to a mixin.
29
+ * Add `column.extraWidth` option (number) for `AposTreeHeader.vue` to allow control over the tree cell width.
30
+ * Move `AposDocContextMenu.vue` business logic to a mixin.
31
+ * Move Pages Manager modal business logic to a mixin. Add `column.extraWidth` option (number) for `AposTreeHeader.vue` to allow control over the tree cell width.
32
+
33
+ ### Changes
34
+
35
+ * Rename misleading `projection` parameter into `options` in `self.find` method signature for
36
+ `@apostrophecms/any-doc-type`, `@apostrophecms/any-page-type` & `@apostrophecms/piece-type`.
37
+ **This was never really a projection in A3,** so it is not a backwards compatibility issue.
38
+ * Hide save button during in-context editing if the document is autopublished.
39
+ * Beginning with this release, the correct `moduleName` for typical
40
+ actions on the context document is automatically passed to the
41
+ modal associated with a custom context operation, unless `moduleName`
42
+ is explicitly specified. The `moduleName` parameter to `addContextOperation`
43
+ is no longer required and should not be passed at all in most cases
44
+ (just pass the object argument). If you do wish to specify a `moduleName`
45
+ to override that prop given to the modal, then it is recommended to pass
46
+ it as a `moduleName` property of the object, not as a separate argument.
47
+ For backwards compatibility the two-argument syntax is still permitted.
48
+
49
+ ### Fixes
50
+
51
+ * Resolved data integrity issue with certain page tree operations by inferring the best peer to position the page relative to rather
52
+ than attempting to remember the most recent move operation.
53
+ * Fixes a downstream bug in the `getFieldsByCategory` method in the `AposEditorMixin.js` by checking for a property before accessing it.
54
+ * In Nunjucks templates, `data.url` now includes any sitewide and locale URL prefixes. This fixes local prefixing for pagination of piece-type index pages.
55
+ * Changes were detected in various fields such as integers, which caused the "Update" button to be active even when there was no actual modification in the doc.
56
+ * Fix a bug that prevented adding multiple operations in the same batch operation group.
57
+ * The `getTarget` method of the page module should use `findForEditing` to make sure it is able to see
58
+ pages that would be filtered out of a public view by project level or npm module overrides.
59
+
3
60
  ## 3.53.0 (2023-08-03)
4
61
 
5
62
  ### Adds
@@ -33,7 +90,7 @@ their modal and a `docProps` object to map properties from the document
33
90
  to props of their choosing.
34
91
  * Adds support to add context labels in admin bar.
35
92
  * Adds support for admin UI language configuration in the `@apostrophecms/i18n` module. The new options allow control over the default admin UI language and configures the list of languages, that any individual logged in user can choose from. See the [documentation](https://v3.docs.apostrophecms.org/reference/modules/i18n.html) for more details.
36
- * Adds `adminLocale` User field to allow users to set their preferred admin UI language, but only when the `@apostrophecms/i18n` is configured accordingly (see above).
93
+ * Adds `adminLocale` User field to allow users to set their preferred admin UI language, but only when the `@apostrophecms/i18n` is configured accordingly (see above).
37
94
  * Adds `@apostrophecms/settings` module and a "Personal Settings" feature. See the [documentation](https://v3.docs.apostrophecms.org/reference/modules/settings.html) for more details.
38
95
  * Adds `$and` operator on `addContextOperation` `if` property in order to check multiple fields before showing or hiding a context operation.
39
96
 
package/defaults.js CHANGED
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
2
  modules: {
3
+ '@apostrophecms/log': {},
3
4
  '@apostrophecms/error': {},
4
5
  '@apostrophecms/util': {},
5
6
  '@apostrophecms/i18n': {},
@@ -36,7 +36,7 @@
36
36
  :show-preview="false"
37
37
  />
38
38
  <AposButton
39
- v-if="canSwitchToPreviewMode"
39
+ v-if="canSwitchToPreviewMode && !isAutopublished"
40
40
  class="apos-admin-bar__context-button"
41
41
  label="apostrophe:preview" :tooltip="{
42
42
  content: 'apostrophe:previewTooltip',
@@ -46,7 +46,7 @@
46
46
  @click="switchEditMode(false)"
47
47
  />
48
48
  <AposButton
49
- v-if="editMode"
49
+ v-if="editMode && !isAutopublished"
50
50
  type="primary" :label="publishLabel"
51
51
  :disabled="!readyToPublish"
52
52
  class="apos-admin-bar__btn apos-admin-bar__context-button"
@@ -125,6 +125,9 @@ export default {
125
125
  }
126
126
  }
127
127
  },
128
+ isAutopublished() {
129
+ return this.context._aposAutopublish ?? (window.apos.modules[this.context.type].autopublish || false);
130
+ },
128
131
  hasBeenPublishedThisPageload() {
129
132
  return (this.context.lastPublishedAt > this.mountedAt) || ((this.context.submitted && this.context.submitted.at) > this.mountedAt);
130
133
  },
@@ -18,25 +18,30 @@
18
18
  <span class="apos-admin-bar__title__document-title">
19
19
  {{ context.title }}
20
20
  </span>
21
- <span class="apos-admin-bar__title__separator">
22
-
23
- </span>
24
- <AposContextMenu
25
- v-if="!isUnpublished"
26
- class="apos-admin-bar__title__document"
27
- :button="draftButton"
28
- :menu="draftMenu"
29
- :disabled="hasCustomUi || isUnpublished"
30
- @item-clicked="switchDraftMode"
31
- menu-offset="13, 10"
32
- menu-placement="bottom-end"
33
- />
34
- <AposLabel
35
- v-else
36
- :label="'apostrophe:draft'"
37
- :tooltip="'apostrophe:notYetPublished'"
38
- :modifiers="['apos-is-warning', 'apos-is-filled']"
39
- />
21
+ <div
22
+ v-if="!isAutopublished"
23
+ class="apos-admin-bar__title__context"
24
+ >
25
+ <span class="apos-admin-bar__title__separator">
26
+
27
+ </span>
28
+ <AposContextMenu
29
+ v-if="!isUnpublished"
30
+ class="apos-admin-bar__title__document"
31
+ :button="draftButton"
32
+ :menu="draftMenu"
33
+ :disabled="hasCustomUi || isUnpublished"
34
+ @item-clicked="switchDraftMode"
35
+ menu-offset="13, 10"
36
+ menu-placement="bottom-end"
37
+ />
38
+ <AposLabel
39
+ v-else
40
+ :label="'apostrophe:draft'"
41
+ :tooltip="'apostrophe:notYetPublished'"
42
+ :modifiers="['apos-is-warning', 'apos-is-filled']"
43
+ />
44
+ </div>
40
45
  <AposLabel
41
46
  class="apos-admin-bar__title-context-label"
42
47
  v-for="{id, label, tooltip = '', modifiers = []} in moduleOptions.contextLabels"
@@ -117,6 +122,9 @@ export default {
117
122
  },
118
123
  moduleOptions() {
119
124
  return window.apos.adminBar;
125
+ },
126
+ isAutopublished() {
127
+ return this.context._aposAutopublish ?? (window.apos.modules[this.context.type].autopublish || false);
120
128
  }
121
129
  },
122
130
  mounted() {
@@ -148,6 +156,7 @@ export default {
148
156
  align-items: center;
149
157
  white-space: nowrap;
150
158
 
159
+ &__context,
151
160
  &__document-title,
152
161
  &__separator {
153
162
  display: inline-flex;
@@ -2,8 +2,8 @@ module.exports = {
2
2
  extend: '@apostrophecms/doc-type',
3
3
  extendMethods(self) {
4
4
  return {
5
- find(_super, req, criteria, projection) {
6
- return _super(req, criteria, projection).type(false);
5
+ find(_super, req, criteria, options) {
6
+ return _super(req, criteria, options).type(false);
7
7
  }
8
8
  };
9
9
  }
@@ -59,8 +59,8 @@ module.exports = {
59
59
 
60
60
  extendMethods(self) {
61
61
  return {
62
- find(_super, req, criteria, projection) {
63
- return _super(req, criteria, projection).type(false).isPage(true);
62
+ find(_super, req, criteria, options) {
63
+ return _super(req, criteria, options).type(false).isPage(true);
64
64
  },
65
65
  // Returns a MongoDB projection object to be used when querying
66
66
  // for this type if all that is needed is a title for display
@@ -322,8 +322,7 @@ module.exports = {
322
322
  path: { $exists: 1 },
323
323
  slug: /^\//
324
324
  }).project({
325
- path: 1,
326
- aposLastTargetId: 1
325
+ path: 1
327
326
  }).toArray();
328
327
  for (const pair of pairs) {
329
328
  const [ from, to ] = pair;
@@ -386,15 +385,6 @@ module.exports = {
386
385
  }
387
386
  if (isPage) {
388
387
  for (const page of pages) {
389
- if (page.aposLastTargetId === from) {
390
- await self.apos.doc.db.updateOne({
391
- _id: page._id
392
- }, {
393
- $set: {
394
- aposLastTargetId: to
395
- }
396
- });
397
- }
398
388
  if (page.path.includes(oldAposDocId)) {
399
389
  await self.apos.doc.db.updateOne({
400
390
  _id: page._id
@@ -1147,40 +1137,76 @@ module.exports = {
1147
1137
  'slug'
1148
1138
  ];
1149
1139
  },
1150
- // Add context menu operation to be used in AposDocContextMenu.
1151
- // Expected operation format is:
1140
+
1141
+ // Add a context menu operation to be offered in AposDocContextMenu, the
1142
+ // "kebab menu" that provides extra operations on the current document or
1143
+ // a document listed in a manager modal.
1144
+ //
1145
+ // The required format is:
1146
+ //
1152
1147
  // {
1153
1148
  // context: 'update',
1154
1149
  // action: 'someAction',
1155
1150
  // modal: 'ModalComponent',
1156
- // label: 'Context Menu Label',
1157
- // conditions: ['canEdit']
1151
+ // label: 'Context Menu Item Label',
1152
+ // conditions: ['canEdit'],
1153
+ // moduleName: 'some-specific-module'
1158
1154
  // }
1159
- // All properties are required except conditions.
1160
- // The only supported `context` for now is `update`.
1155
+ //
1156
+ // All properties are required except for `conditions`, `moduleName`,
1157
+ // `modifiers` and `manuallyPublished`.
1158
+ //
1159
+ // Context operations are universal, e.g. they are displayed by the context
1160
+ // menu no matter what the content type is, unless overridden by `conditions`.
1161
+ //
1161
1162
  // `action` is the operation identifier and should be globally unique.
1162
- // Overriding existing custom actions is possible (the last wins).
1163
- // `modal` is the name of the modal component to be opened.
1164
- // `label` is the menu label to be shown when expanding the context menu.
1165
- // Additional optional `modifiers` property is supported - button modifiers
1163
+ // For convenience, if several modules add an operation with the same `action`,
1164
+ // it is only added once. This prevents duplicates if all subclasses of
1165
+ // `doc-type` or `piece-type` register the same operation.
1166
+ //
1167
+ // `context` currently must be `update`.
1168
+ //
1169
+ // `modal` is the name of the modal component to be opened by the operation.
1170
+ //
1171
+ // `label` is the menu item label to be shown when expanding the context menu.
1172
+ //
1173
+ // An additional `moduleName` property is supported. If it is not given,
1174
+ // it will be inferred from the `type` of the document in context, with all page
1175
+ // types using the page module (not their type-specific module). This is almost
1176
+ // always correct, therefore it only makes sense to pass an explicit
1177
+ // `moduleName` option here if the action API should be invoked on a different module
1178
+ // than expected.
1179
+ //
1180
+ // An additional optional `modifiers` property is supported - button modifiers
1166
1181
  // as supported by `AposContextMenu` (e.g. modifiers: [ 'danger' ]).
1182
+ //
1167
1183
  // An optional `manuallyPublished` boolean property is supported - if true
1168
1184
  // the menu will be shown only for docs which have `autopublish: false` and
1169
1185
  // `localized: true` options.
1170
- // `conditions` defines the needed permission actions to be run on the current doc
1171
- // in order to display the operation.
1172
- // It must be an array containing one or multiple of these available values:
1186
+ //
1187
+ // `conditions` defines the circumstances under which the opetion should be displayed.
1188
+ // If all `conditions` are not met, the item is not displayed for this particular
1189
+ // document.
1190
+ //
1191
+ // `conditions` may be an array containing one or multiple of these values:
1192
+ //
1173
1193
  // 'canPublish', 'canEdit', 'canDismissSubmission', 'canDiscardDraft',
1174
1194
  // 'canLocalize', 'canArchive', 'canUnpublish', 'canCopy', 'canRestore'.
1175
- addContextOperation(moduleName, operation) {
1195
+
1196
+ addContextOperation(operation) {
1197
+ if (arguments.length === 2) {
1198
+ // For backwards compatibility. `moduleName` is rarely needed
1199
+ // so it should not be a separate argument in new code.
1200
+ operation = {
1201
+ ...arguments[1],
1202
+ moduleName: arguments[0]
1203
+ };
1204
+ }
1176
1205
  validate(operation);
1177
1206
  self.contextOperations = [
1178
1207
  ...self.contextOperations
1179
1208
  .filter(op => op.action !== operation.action),
1180
- {
1181
- ...operation,
1182
- moduleName
1183
- }
1209
+ operation
1184
1210
  ];
1185
1211
 
1186
1212
  function validate ({
@@ -415,7 +415,7 @@ module.exports = {
415
415
  }
416
416
  },
417
417
  addContextMenu() {
418
- self.apos.doc.addContextOperation(self.__meta.name, {
418
+ self.apos.doc.addContextOperation({
419
419
  action: 'shareDraft',
420
420
  context: 'update',
421
421
  label: 'apostrophe:shareDraft',
@@ -1054,10 +1054,14 @@ module.exports = {
1054
1054
  });
1055
1055
  } else {
1056
1056
  // A page that is not the home page, being replicated for the first time
1057
- const lastTargetId = draft.aposLastTargetId;
1058
- let lastPosition = draft.aposLastPosition;
1057
+ let { lastTargetId, lastPosition } = await self.apos.page.inferLastTargetIdAndPosition(draft);
1059
1058
  let localizedTargetId = lastTargetId.replace(`:${draft.aposLocale}`, `:${toLocale}:draft`);
1060
- const localizedTarget = await actionModule.find(toReq, self.apos.page.getIdCriteria(localizedTargetId)).archived(null).areas(false).relationships(false).toObject();
1059
+ const localizedTarget = await actionModule
1060
+ .find(toReq, self.apos.page.getIdCriteria(localizedTargetId))
1061
+ .archived(null)
1062
+ .areas(false)
1063
+ .relationships(false)
1064
+ .toObject();
1061
1065
  if (!localizedTarget) {
1062
1066
  if ((lastPosition === 'firstChild') || (lastPosition === 'lastChild')) {
1063
1067
  throw self.apos.error('notfound', req.t('apostrophe:parentNotLocalized'), {
@@ -1071,9 +1075,10 @@ module.exports = {
1071
1075
  // Almost impossible (race conditions like someone removing it while we're in the modal)
1072
1076
  throw self.apos.error('notfound');
1073
1077
  }
1074
- const localizedTarget = await actionModule.find(toReq, {
1078
+ const criteria = {
1075
1079
  path: self.apos.page.getParentPath(originalTarget)
1076
- }).archived(null).areas(false).relationships(false).toObject();
1080
+ };
1081
+ const localizedTarget = await actionModule.find(toReq, criteria).archived(null).areas(false).relationships(false).toObject();
1077
1082
  if (!localizedTarget) {
1078
1083
  throw self.apos.error('notfound', req.t('apostrophe:parentNotLocalized'), {
1079
1084
  // Also provide as data for code that prefers to localize client side